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

时间:2017-06-27 10:32:39

标签: spring-boot spring-security spring-security-oauth2

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

我的网络应用是一个有状态(vaadin)的webapp。它使用会话来处理很多东西,我无法使用它。使用OAuth进行身份验证后,它将使用"以前经过身份验证:org.springframework.security.oauth2.provider.OAuth2Authentication"检查它是否经过验证,我认为这只是" true"直到会议被销毁。

我的休息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"));
    }

}

3 个答案:

答案 0 :(得分:1)

总体上,我花了一天时间研究这个问题以及OAuth2的机制。我可以确认访问令牌过期后未刷新的上述发现是正确的。在令牌过期之前或之后,对象身份验证永远不会更改。但我发现了一种无需发送401即可刷新令牌的复杂方法。 我使用了this tutorial

中的一些代码

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

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);
}

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

http.addFilterBefore(customFilter, AnonymousAuthenticationFilter.class);

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

但是问题仍然存在,是否曾经打算以这种方式使用此属性。也许这个到期时间是从发行令牌到客户端收到令牌之间的时间?如果令牌在过期后到达,则会引发异常。也许这应该是这样工作的?

答案 1 :(得分:0)

我最终使用默认令牌代替jwt并使用auth服务器的tokencheck端点进行检查。这样就可以对每个请求进行验证。

答案 2 :(得分:0)

通过添加过滤器来解决此问题的解决方法,该过滤器检查访问令牌是否已过期并发送401响应。此响应在UI端处理,并要求用户刷新会话。刷新会话时,也会刷新访问令牌。解决方案适用于JWT。

代码:

@Component
public class ExpiredTokenFilter implements Filter {

    @Autowired
    private OAuth2ClientContext oAuth2ClientContext;

    @Override
    public void doFilter(ServletRequest servletRequest...) throws... {
        OAuth2AccessToken accessToken = oAuth2ClientContext.getAccessToken();
        if (accessToken != null && accessToken.isExpired()) {
             HttpServletResponse httpServletReponse = (HttpServletResponse) servletResponse;
             httpServletReponse.sendError(401);
             return;
        }
    }
    /* ... rest of code */
}