首页 文章

Spring Security:OAuth2自定义过滤器,用于验证密码过期错误处理

提问于
浏览
2

我一直在尝试实现OAuth2密码到期过滤器,我不确定这样做的正确方法 . 想法如下:

  • 用户尝试登录 .

  • 如果密码已过期,用户将获得包含令牌的标头的响应 .

  • 用户使用该令牌重定向到密码更改页面(即/ password-change / ) .

  • 他提交了他的旧密码和新密码,它会被更改 .

  • 某些其他控制器通过该令牌检索用户ID,并执行其余密码更改逻辑 .

  • 用户应该被重定向回初始登录页面,在那里他用新密码登录(如果他在密码更改后立即登录,他可以浏览安全页面,即使密码不会因为某些人而在后台更改例外等) .

所以......我在密码过期的用户详细信息中设置了一个自定义标志,因为我在DaoAuthenticationProvider中验证它时不能使用credentialsNonExpired,并作为异常被抛出,因为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之后被放置,而's no BasicAuthenticationFilter in the chain? I'已经通过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客户端的密码?

1 回答

  • 0

    好吧,我想我通过在我的过滤器中注入TokenStore来撤销访问令牌来解决这个问题(我使用BearerTokenExtractor获取令牌值),这在这个看起来很合乎逻辑 . 我仍然没有时间弄明白,为什么我的过滤器放在OAuth2AuthenticationProcessingFilter之后 .

相关问题