Spring执行两次,第一次成功,然后失败

时间:2016-12-27 10:55:19

标签: spring session authentication login spring-security

我试图围绕Spring Security框架,并使用自定义AuthenticationProvider实现身份验证

当我导航到安全网址并使用正确的凭据进行登录时,会进行两次登录尝试。第一次成功,第二次失败,浏览器停留在登录页面,没有错误消息。

这是我的安全配置。

package training2;

{ imports... }

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("myProvider")
    private AuthenticationProvider provider;

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .permitAll()
            .and()
            .logout()
            .permitAll();
    }

    @Override
    public UserDetailsService userDetailsServiceBean() throws Exception {
        // TODO Auto-generated method stub
        return super.userDetailsServiceBean();
    }

    @Override
    @Bean
    protected UserDetailsService userDetailsService() {
        return new UserDetailsService() {

            public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
                System.out.println("loadUserByUsername");

                return new UserDetails() {

                    private static final long serialVersionUID = -1044116648365271684L;

                    public boolean isEnabled() {
                        // TODO Auto-generated method stub
                        return true;
                    }

                    public boolean isCredentialsNonExpired() {
                        // TODO Auto-generated method stub
                        return true;
                    }

                    public boolean isAccountNonLocked() {
                        // TODO Auto-generated method stub
                        return true;
                    }

                    public boolean isAccountNonExpired() {
                        // TODO Auto-generated method stub
                        return true;
                    }

                    public String getUsername() {
                        // TODO Auto-generated method stub
                        return username;
                    }

                    public String getPassword() {
                        // TODO Auto-generated method stub
                        return "asdf";
                    }

                    public Collection<? extends GrantedAuthority> getAuthorities() {
                        // TODO Auto-generated method stub
                        return null;
                    }
                };
            }
        };
    }

    @Bean
    @Qualifier("myProvider")
    public AuthenticationProvider myProvider(final UserDetailsService userDetailsService) {
        return new AuthenticationProvider() {

            public boolean supports(Class<?> authentication) {
                return true;
            }

            public Authentication authenticate(Authentication authentication) throws AuthenticationException {
                System.out.println("authenticate");

                UserDetails user = userDetailsService.loadUserByUsername(authentication.getName());
                if (user != null && user.getPassword().equals(authentication.getCredentials())) {
                    System.out.println("authentication ok");
                    return authentication;
                } else {
                    System.out.println("authentication failed");
                    throw new AuthenticationException(null) {
                        private static final long serialVersionUID = -1022654748424786317L;
                    };
                }
            }
        };
    }
}

尝试使用有效凭据登录时,控制台中会打印出以下内容

authenticate
loadUserByUsername
authentication ok
authenticate
loadUserByUsername
authentication failed

尝试使用无效凭据(密码除 asdf 之外的任何密码)登录时,身份验证仅执行一次,并且应该失败。

为什么在表单登录时执行两次身份验证,首先成功然后失败?是错误的配置,还是我错过了一些豆?另外,我应该手动管理SecurityContext,使用自定义AuthenticationProvider实现,还是Spring仍然管理它以及在哪里?

我也很困惑,为什么我必须明确地将userDetailsService方法注释为@Bean才能进行Spring管理,即使WebSecurityConfigurer声明了这种方法。

1 个答案:

答案 0 :(得分:2)

.anyRequest().authenticated()

因此,它会检查身份验证是否在FilterSecurityInterceptor中进行了身份验证,但您的提供程序中返回的身份验证未经过身份验证,FilterSecurityInterceptor将再次执行authenticate

if (user != null && user.getPassword().equals(authentication.getCredentials())) {
    System.out.println("authentication ok");
    // should authenticated authenticaiton
    //return new UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities)
}