我试图围绕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
声明了这种方法。
答案 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)
}