स्प्रिंग 4.1 और स्प्रिंग सिक्योरिटी 3.2: हमने एक कस्टम ऑथेंटिकेशन प्रोवाइडर को लागू किया है, जो कि BadCredentialsException को फेंकता है अगर यूजर गलत पासवर्ड डालता है। जब BadCredentialsException को फेंक दिया जाता है, तो ProviderManager.authenticate विधि को कहा जाता है, जो कस्टम प्रमाणीकरण में फिर से प्रमाणित विधि को कॉल करता है। जब एक LockedException को फेंक दिया जाता है, तो कस्टम प्रमाणीकरण प्रदाता में पुराने तरीके को फिर से नहीं कहा जाता है। हम लॉगिन प्रयासों की संख्या को ध्यान में रखते हुए योजना बना रहे हैं, इसलिए हम दो बार प्रमाणित विधि नहीं चाहते हैं। क्या किसी को पता है कि कस्टम प्रमाणीकरण वर्ग में प्रामाणिक विधि को दो बार क्यों कहा जाएगा?

WebConfig:


  @Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    @Autowired
    private AMCiUserDetailsService userDetailsService;

    @Autowired
    private CustomImpersonateFailureHandler impersonateFailureHandler;

    @Autowired
    private LoginFailureHandler loginFailureHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
                .antMatchers("/jsp/*.css","/jsp/*.js","/images/**").permitAll()  
                .antMatchers("/login/impersonate*").access("hasRole('ADMIN') or hasRole('ROLE_PREVIOUS_ADMINISTRATOR')") 
                .anyRequest().authenticated()                                    
                .and()
            .formLogin()
                .loginPage("/login.jsp")
                .defaultSuccessUrl("/jsp/Home.jsp",true)                
                .loginProcessingUrl("/login.jsp")                                 
                .failureHandler(loginFailureHandler)
                .permitAll()
                .and()
            .logout()
                .logoutSuccessUrl("/login.jsp?msg=1")
                .permitAll()
                .and()
            .addFilter(switchUserFilter())
            .authenticationProvider(customAuthenticationProvider);

            http.exceptionHandling().accessDeniedPage("/jsp/SecurityViolation.jsp");  //if user not authorized to a page, automatically forward them to this page.
            http.headers().addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN)); 
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    //Used for the impersonate functionality
    @Bean CustomSwitchUserFilter switchUserFilter() {
        CustomSwitchUserFilter filter = new CustomSwitchUserFilter();
        filter.setUserDetailsService(userDetailsService);
        filter.setTargetUrl("/jsp/Impersonate.jsp?msg=0");
        filter.setSwitchUserUrl("/login/impersonate");
        filter.setExitUserUrl("/logout/impersonate");
        filter.setFailureHandler(impersonateFailureHandler);
        return filter;
    }
}

कस्टम प्रमाणीकरण प्रदाता:

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Autowired(required = true)
    private HttpServletRequest request;

    @Autowired
    private AMCiUserDetailsService userService;

    @Autowired
    private PasswordEncoder encoder;

    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        String username = authentication.getName().trim();
        String password = ((String) authentication.getCredentials()).trim();
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            throw new BadCredentialsException("Login failed! Please try again.");
        }


        UserDetails user;
        try {
            user = userService.loadUserByUsername(username);
            //log successful attempt
            auditLoginBean.setComment("Login Successful");
            auditLoginBean.insert(); 
        } catch (Exception e) {
             try {
                //log unsuccessful attempt
                auditLoginBean.setComment("Login Unsuccessful");
                auditLoginBean.insert();
             } catch (Exception e1) {
                // TODO Auto-generated catch block
             }
            throw new BadCredentialsException("Please enter a valid username and password.");
        }

        if (!encoder.matches(password, user.getPassword().trim())) {
            throw new BadCredentialsException("Please enter a valid username and password.");
        }

        if (!user.isEnabled()) {
            throw new DisabledException("Please enter a valid username and password.");
        }

        if (!user.isAccountNonLocked()) {
            throw new LockedException("Account locked. ");
        }

        Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
        List<GrantedAuthority> permlist = new ArrayList<GrantedAuthority>(authorities);

        return new UsernamePasswordAuthenticationToken(user, password, permlist);
    }


    public boolean supports(Class<? extends Object> authentication) {
        return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
    }
6
Maria Speicher 18 नवम्बर 2015, 21:56

2 जवाब

सबसे बढ़िया उत्तर

कारण यह है कि आप अपने प्रमाणीकरण प्रदाता को दो बार जोड़ते हैं, एक बार configure(HttpSecurity) में और एक बार configure(AuthenticationManagerBuilder) में। यह दो आइटमों के साथ ProviderManager बनाएगा, दोनों आपके प्रदाता होने के नाते।

जब प्रमाणीकरण संसाधित किया जाता है, तो प्रदाताओं को तब तक क्रम में पूछा जाएगा जब तक कि कोई सफलता नहीं बन जाती, जब तक LockedException या समान स्थिति अपवाद नहीं फेंकी जाती है, तो लूप टूट जाएगा।

8
holmis83 19 नवम्बर 2015, 08:37

ऐसी स्थिति हो सकती है जिसे आप configure(AuthenticationManagerBuilder) और अभी भी AuthenticationProver 's authenticate को ओवरराइड नहीं करते हैं, विधि को स्वीकृत उत्तर में उसकी टिप्पणी में उल्लेखित फिल की तरह दो बार बुलाया जाता है।

ऐसा क्यों है?

कारण यह है कि जब आप configure(AuthenticationManagerBuilder) को ओवरराइड नहीं करते हैं और AuthenticationProvider सेम है, तो इसे स्प्रिंग सिक्योरिटी द्वारा पंजीकृत किया जाएगा, आपको कुछ और करने की जरूरत नहीं है।

हालाँकि, जब configure(AuthenticationManagerBuilder) ओवरराइड हो जाता है, तो स्प्रिंग सिक्योरिटी इसे लागू करेगी और किसी भी प्रदाता को खुद से पंजीकृत करने की कोशिश नहीं करेगी। यदि आप उत्सुक हैं, तो आप संबंधित विधिdisableLocalConfigureAuthenticationBldr सत्य है यदि आप configure(AuthenticationManagerBuilder) ओवरराइड करते हैं।

इसलिए, संक्षेप में, यदि आप सिर्फ एक रिवाज AuthenticationProvider रजिस्टर करना चाहते हैं, तो configure(HttpSecurity) authenticationProvider(AuthenticationProvider) में कॉल न करें, configure(HttpSecurity) को ओवरराइड न करें, बस अपना AuthenticationProviver करें। @Component एनोटेट करके कार्यान्वयन बीन और आप जाने के लिए अच्छे हैं।

2
sedooe 18 जिंदा 2018, 13:07