【发布时间】:2015-11-18 08:28:15
【问题描述】:
我一直在尝试实现 OAuth2 密码过期过滤器,但我不确定这样做的正确方法是什么。思路如下:
- 用户尝试登录。
- 如果密码过期,用户会收到带有包含令牌的标头的响应。
- 使用该令牌(即 /password-change/{token})将用户重定向到密码更改页面。
- 他提交了他的旧密码和新密码,它被更改了。
- 一些休息控制器通过该令牌检索用户 ID 并执行休息密码更改逻辑。
- 应将用户重定向回初始登录页面,在该页面中他使用新密码登录(如果他在密码更改后立即登录,即使密码不会在后台更改,他也可以浏览安全页面某些例外等)。
所以...我在用户详细信息中设置了一个自定义标志以用于密码过期,因为我无法使用 credentialsNonExpired,因为它在 DaoAuthenticationProvider 中得到验证并作为异常抛出,该异常作为 InvalidGrantException 处理,这并没有给我太多控制权。我发现为了在身份验证后立即访问用户详细信息,我的过滤器应该位于 OAuth2AuthenticationProcessingFilter 之后放置的内部 Spring Security 过滤器链中:
@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
...
http.addFilterAfter(new PasswordExpirationFilter(), BasicAuthenticationFilter.class
}
}
- 为什么我的过滤器放在 OAuth2AuthenticationProcessingFilter 之后,而链中没有 BasicAuthenticationFilter?我浏览了 Spring Security 和 OAuth2 文档和资源,但找不到正确的答案。
-
如果该用户的密码已过期,我的过滤器会生成一些随机字符串并将其保存,以便稍后在密码更改请求期间检索用户详细信息(至少应该如此):
public class PasswordExpirationFilter extends OncePerRequestFilter implements Filter, InitializingBean { private static final String TOKEN_HEADER = ...; private ExpiredPasswordRepository repo; // gets set in a constructor and is basically holding a concurrent map of tokens ... protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { UserDetails details = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if (details.isPasswordExpired) { String uuid = UUID.randomUUID().toString(); repo.push(uuid, details.getId()); SecurityContextHolder.clearContext(); SecurityContextHolder.getContext().setAuthentication(null); request.getSession(false).invalidate(); // don't create a new session response.addHeader(TOKEN_HEADER, uuid); response.sendError(HttpStatus.SC_PRECONDITION_FAILED, "Credentials have expired"); } else { filterChain.doFilter(request, response); } } }
我是否也必须撤销 OAuth 令牌?它在以后的请求中被重用,我不断得到最后一个 userDetails 对象,因此我不断从我的过滤器中得到相同的响应。
- 它是否适合进行所有这些验证?应该如何验证具体用户而不是 OAuth 客户端的密码?
【问题讨论】:
标签: java spring spring-security spring-boot spring-security-oauth2