Spring Security Context Set Authentication 对象不起作用
Posted
技术标签:
【中文标题】Spring Security Context Set Authentication 对象不起作用【英文标题】:Spring Security Context Set Authentication object not working 【发布时间】:2012-03-07 12:40:49 【问题描述】:我有一个场景,我必须强制用户在首次登录时重置密码。为了 我正在使用自定义的successAuthenticationHandler。 所有这个处理程序试图做的是查看登录用户是否需要重置密码。如果是,则创建一个新的 UsernamePasswordAuthenticationToken 并将其设置到 SecurityContext。然后重定向到resetPasswordUrl。
这是我的 onAuthenticationSuccess 方法:
@Override
public void onAuthenticationSuccess(final HttpServletRequest request, final HttpServletResponse response,
final Authentication authentication) throws ServletException, IOException
final AugmentedUser aUser = (AugmentedUser) SecurityContextHolder.getContext().getAuthentication()
.getPrincipal();
System.out.println("In password reset handler.");
if (authorizationService.isPasswordResetRequired(aUser.getUsername(), aUser.getUsertype()))
LOG.debug("Password reset is required.");
System.out.println("Password reset is required");
final UsernamePasswordAuthenticationToken authRequest = reAssignUserWithOnlyResetPasswordRole(aUser,
request);
SecurityContextHolder.getContext().setAuthentication(authRequest);
SecurityContextHolder.getContext().getAuthentication();
System.out.println("User reassinged with only RESET_PASSWORD Authority, redirecting to resetPasswordPage");
response.sendRedirect(resetPasswordUrl);
//super.onAuthenticationSuccess(request, response, newAuthentication);
else
super.onAuthenticationSuccess(request, response, authentication);
如果是,则使用与登录用户相同的凭据创建另一个 UsernamePasswordAuthenticationToken,但只需为他分配一个角色“RESET_PASSWORD”,这样他就无法通过点击任何其他链接/url 来访问任何其他内容。
private UsernamePasswordAuthenticationToken reAssignUserWithOnlyResetPasswordRole(final AugmentedUser aUser,
final HttpServletRequest request)
final String username = aUser.getUsername();
final String password = aUser.getPassword();
final boolean isEnabled = aUser.isEnabled();
final boolean isAccountNonExpired = aUser.isAccountNonExpired();
final boolean isCredentialsNonExpired = aUser.isCredentialsNonExpired();
final boolean isAccountNonLocked = aUser.isAccountNonLocked();
LOG.debug("Re-assigning the user: " + username + " with only RESET PASSWORD AUTHORITY");
System.out.println("Re-assigning the user: " + username + "with only RESET PASSWORD AUTHORITY");
final Map<String, String> userAttributesMap = new HashMap<String, String>();
final AugmentedUser userWithResetPasswordRole = new AugmentedUser(username, password, aUser.getUsertype(),
isEnabled, isAccountNonExpired, isCredentialsNonExpired, isAccountNonLocked,
createResetPasswordGrantedAuhtority(), userAttributesMap);
final UsernamePasswordAuthenticationToken authenticationRequest = new UsernamePasswordAuthenticationToken(
userWithResetPasswordRole, userWithResetPasswordRole.getAuthorities());
//WebAuthenticationDetails are required for sessionId and ipAddress
final WebAuthenticationDetails webAuthenticationDetails = new WebAuthenticationDetails(request);
authenticationRequest.setDetails(webAuthenticationDetails);
return authenticationRequest;
现在我确实看到新的 UsernamePasswordAuthenticationToken 仅使用 RESET 密码角色创建。 但是看起来在重定向到 resetPasswordURl 时,spring 过滤器会进行一些检查,并且在我设置了新的 UsernamePasswordAuthenticationToken 之后,用户正在未经身份验证。
这是我在日志中看到的根本原因:
doAuthentication - Authentication attempt using
org.springframework.security.authentication.dao.DaoAuthenticationProvider
2012-02-15 22:47:20,931 [http-8081-6] DEBUG org.springframework.security.web.access.ExceptionTranslationFilter org.springframework.security.web.access.ExceptionTranslationFilter handleException - Authentication exception occurred; redirecting to authentication entry point
org.springframework.security.authentication.BadCredentialsException: Bad credentials
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticationChecks(DaoAuthenticationProvider.java:67)
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:139)
at org.springframework.security.authentication.ProviderManager.doAuthentication(ProviderManager.java:120)
我哪里出错了?
【问题讨论】:
【参考方案1】:如果没有来自日志的更多上下文(堆栈跟踪的其余部分加上前面的日志消息),很难说,但我最好的猜测是您为UsernamePasswordAuthenticationToken
使用了错误的构造函数。由于历史原因,它需要 Object
参数,这没有帮助。
双参数版本应该采用用户名和凭据,并创建一个未经身份验证的令牌(用于请求),从安全拦截器的角度来看这是无效的。所以我猜测拦截器正在尝试重新验证令牌(应该从调用来自的堆栈跟踪中显而易见)并且它失败了,因为凭据参数实际上是权限列表而不是密码。
所以使用:
new UsernamePasswordAuthenticationToken(
userWithResetPasswordRole, null, userWithResetPasswordRole.getAuthorities());
改为。
此外,您需要有一个处理RESET_PASSWORD
的自定义投票器,因为默认配置无法识别它。或者使用ROLE_
前缀,即ROLE_RESET_PASSWORD
。
【讨论】:
以上是关于Spring Security Context Set Authentication 对象不起作用的主要内容,如果未能解决你的问题,请参考以下文章
Spring:HttpSession在集群Tomcat故障转移中为SPRING_SECURITY_CONTEXT返回了空对象
Spring Security Context Set Authentication 对象不起作用