当令牌不再有效时,Spring 安全 OAuth 身份验证不会过期

p.s*_*eef 5 spring-security spring-boot spring-security-oauth2

我正在使用 Spring security 和 spring oauth 在我的 Web 应用程序中进行身份验证(使用 jwt 令牌)。这工作正常,令牌被交换,我可以正确登录。但是,一旦登录,即使令牌过期,身份验证也不会过期。当我尝试重用令牌以从我的资源服务器获取资源时,它返回访问被拒绝,因为令牌不再有效。

我的网络应用程序是一个有状态(vaadin)网络应用程序。它使用会话来处理很多东西,我无法绕过它。使用 OAuth 进行身份验证后,它将使用“以前身份验证:org.springframework.security.oauth2.provider.OAuth2Authentication”来检查它是否已通过身份验证,我似乎这只会是“真”,直到会话被销毁。

我的 rest api 是状态/无会话的,因此每次都会正确验证令牌。如果过期,它将给出 401。

我发现处理这个问题的唯一方法是相当丑陋:如果 api 返回 401,则使会话无效。但是我想看到的是,Web 应用程序还会检查每个请求上令牌的有效性。使用会话时有没有办法做到这一点?

这是我的 webapp 的 oauth 安全配置部分。

@Configuration
@EnableOAuth2Sso
public class OAuthConfig extends WebSecurityConfigurerAdapter
{

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/login**").permitAll()
                .anyRequest().authenticated()
                .and()
                .logout()
                .logoutSuccessUrl("/")
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .and()
                .exceptionHandling().authenticationEntryPoint((request, response, authException) -> response.sendRedirect("/login"));
    }

}
Run Code Online (Sandbox Code Playgroud)

Xal*_*tun 5

我花了一天时间研究这个问题以及 Spring 中 OAuth2 的机制。我可以确认上面的访问令牌过期后不会刷新的结果是正确的。对象 Authentication 在令牌过期之前或之后永远不会更改。但我找到了一种复杂的方法来刷新令牌而不发送 401。我使用了本教程中的一些代码

就是这样。首先创建一个自定义过滤器:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    OAuth2ClientContext ctxt = restTemplate.getOAuth2ClientContext();
    if (ctxt != null) {
        OAuth2AccessToken accessToken = ctxt.getAccessToken();
        if (accessToken != null && accessToken.isExpired()) {
            SecurityContextHolder.getContext().setAuthentication(null);
        }
    }
    chain.doFilter(request, response);
}
Run Code Online (Sandbox Code Playgroud)

如果令牌已过期,此过滤器会将 Authentication 对象设置为 null。该过滤器必须在 AnonymousAuthenticationFilter 之前注册:

http.addFilterBefore(customFilter, AnonymousAuthenticationFilter.class);
Run Code Online (Sandbox Code Playgroud)

AnonymousAuthenticationFilter 将使用“匿名”属性填充身份验证。然后最后一个过滤器将抛出 AccessDeniedException 并开始从服务器获取令牌的过程。仅当 Authentication 对象填充了“匿名”属性时,AccessDeniedException 才能开始获取新令牌的过程。服务器实际上刷新令牌并发送回具有新过期时间的新令牌。

但问题仍然是,该财产是否曾打算以这种方式使用。也许这个过期时间是从令牌发出到客户端收到令牌之前的时间?如果令牌在过期后到达,则会引发异常。也许这就是它应该如何工作?


p.s*_*eef 0

我最终使用默认令牌而不是 jwt 并使用身份验证服务器的 tokencheck 端点进行检查。这样,每个请求都会得到验证。