Mar*_*her 6 spring spring-security
Spring 4.1和Spring Security 3.2:我们实现了一个自定义身份验证提供程序,如果用户输入的密码不正确,则会抛出BadCredentialsException.抛出BadCredentialsException时,将调用ProviderManager.authenticate方法,该方法再次调用自定义身份验证中的authenticate方法.抛出LockedException时,不会再次调用自定义身份验证提供程序中的authenicate方法.我们计划保留登录尝试次数,因此我们不希望将authenticate方法调用两次.有谁知道为什么自定义身份验证类中的authenticate方法将被调用两次?
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;
}
}
Run Code Online (Sandbox Code Playgroud)
定制认证提供商:
@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));
}
Run Code Online (Sandbox Code Playgroud)
原因是您添加了两次身份验证提供程序,一次configure(HttpSecurity)
和一次configure(AuthenticationManagerBuilder)
.这将创建一个ProviderManager
包含两个项目,两者都是您的提供者.
在处理身份验证,供应商将被要求以直至成功制成,除非一个LockedException
或类似的状况异常被抛出,则循环将打破.
可能有一种情况您没有覆盖,configure(AuthenticationManagerBuilder)
并且仍然调用了相同AuthenticationProver
的authenticate
方法两次,就像 Phil 在他在接受的答案中的评论中提到的那样。
这是为什么?
原因是当你没有覆盖configure(AuthenticationManagerBuilder)
并拥有一个AuthenticationProvider
bean时,它会被Spring Security注册,你不需要做任何其他事情。
但是,当configure(AuthenticationManagerBuilder)
被覆盖时,Spring Security 将调用它并且不会尝试自行注册任何提供程序。如果你好奇,你可以看看相关的方法。disableLocalConfigureAuthenticationBldr
如果您覆盖configure(AuthenticationManagerBuilder)
.
所以,简单地说,如果你想注册只有一个自定义的AuthenticationProvider
话不重写configure(AuthenticationManagerBuilder)
,不叫authenticationProvider(AuthenticationProvider)
的configure(HttpSecurity)
,只是让你AuthenticationProviver
通过注释实现bean @Component
,你是好去。
归档时间: |
|
查看次数: |
2077 次 |
最近记录: |