Spring Security Oauth2:处理过期 AccessToken 的流程

Posted

技术标签:

【中文标题】Spring Security Oauth2:处理过期 AccessToken 的流程【英文标题】:Spring Security Oauth2: Flow to Handling Expired AccessToken 【发布时间】:2015-02-08 04:11:43 【问题描述】:

我只是 Spring Security Oauth2 的初学者。 我尝试制作授权服务器和资源服务器(分离并连接到 JDBC),目的是进行单点登录。 我从授权服务器获取访问令牌和刷新令牌的流程成功。我的 accesstoken 总是作为参数访问 Resouce Server,这是回馈。

for example http://127.0.0.1:8080/Resource/res/staff?access_token=xxxxxxxxxxxxxxxxxxxxx

我的问题,如果accesstoken过期了,spring security会阻止访问页面并给出错误异常。什么时候必须使用 refreshtoken 来获取新令牌? 还是我的流程错了?是否有其他流程可以更新 accesstoken?

谢谢

已编辑:

仅供参考: 我想使用 Spring Security Oauth2 进行 SSO。我有几个 Apps Server(使用 Spring Framework),我想制作一个负责管理登录的服务器。我想让应用服务器成为资源服务器(也是客户端) 所以我用 Spring Security Oauth2 做了一个授权服务器。想要访问受保护资源服务器的用户必须登录到授权服务器(资源服务器授权给授权服务器)。它将获得一个代码,然后资源服务器将与 accessToken 和 refreshToken 交换此代码。这个流程是成功的。

我还可以使用授权服务器提供的 refreshToken 请求新的 accessToken。 但是我不能调用这个过程,因为如果我访问 url 映射,以前 spring security 会阻止访问并返回无效令牌错误。

如何解决丢失的链接?

更新:

这是我的授权服务器配置:

@Configuration
public class Oauth2AuthorizationServer 

 @Configuration
 @EnableAuthorizationServer
 protected static class AuthorizationServerConfiguration extends
        AuthorizationServerConfigurerAdapter 

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Autowired
    DataSource dataSource;


    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints)
            throws Exception 
        endpoints
                .tokenStore(new JdbcTokenStore(dataSource))
                .authenticationManager(authenticationManager);
    

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception 
        oauthServer.tokenKeyAccess("isAnonymous() || permitAll()").checkTokenAccess("permitAll()");
    

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception 
        clients
                .jdbc(dataSource);
    
 

这是我的资源服务器配置(也作为客户端)

@Configuration
public class Oauth2ResourceServer 

private static final String RESOURCE_ID = "test";

 @Configuration @Order(10)
 protected static class NonOauthResources extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.authorizeRequests()
                .antMatchers("/api/halo").permitAll()
                .antMatchers("/api/state/**").permitAll()
                .antMatchers("/**").permitAll()
                .and().anonymous();
    
 

 @Configuration
 @EnableResourceServer
 protected static class ResourceServerConfiguration extends
        ResourceServerConfigurerAdapter 

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) 
        RemoteTokenServices tokenService = new RemoteTokenServices();
        tokenService.setClientId("jsclient");
        tokenService.setClientSecret("jspasswd");
        tokenService.setCheckTokenEndpointUrl("http://localhost:8084/Server2Auth/oauth/check_token");

        resources
                .resourceId(RESOURCE_ID)
                .tokenServices(tokenService);
    

    @Override
    public void configure(HttpSecurity http) throws Exception 
        http.authorizeRequests()
                .filterSecurityInterceptorOncePerRequest(true)
                .antMatchers("/res/staff").hasRole("STAFF")
                .antMatchers("/res/client").access("#oauth2.hasScope('trust')")
                .antMatchers("/res/admin").hasRole("ADMIN")
                .and()
                .exceptionHandling().accessDeniedPage("/403");
    

 


资源(也作为客户端)请求授权:

curl -X POST -vu clientauthcode:123456 http://localhost:10000/auth-server/oauth/token -d "client_id=clientauthcode&grant_type=refresh_token&refresh_token=436761f1-2f26-412b-ab0f-bbf2cd7459c4"

来自授权服务器的反馈:

http://localhost:10001/resource-server/api/state/new?code=8OppiR

资源(作为客户端)将代码交换给授权服务器:

curl -X POST -vu clientauthcode:123456 http://localhost:10000/auth-server/oauth/token -H "Accept: application/json" -d "grant_type=authorization_code&code=iMAtdP&redirect_uri=http://localhost:10001/resource-server/api/state/new"

来自授权服务器的反馈:


    "access_token":"08664d93-41e3-473c-b5d2-f2b30afe7053",
    "token_type":"bearer",
    "refresh_token":"436761f1-2f26-412b-ab0f-bbf2cd7459c4",
    "expires_in":43199,
    "scope":"write read"

资源(作为客户端)访问 url 本身

curl http://localhost:10001/resource-server/api/admin?access_token=08664d93-41e3-473c-b5d2-f2b30afe7053

使用刷新令牌请求新的访问令牌

curl -X POST -vu clientauthcode:123456 http://localhost:10000/auth-server/oauth/token -d "client_id=clientauthcode&grant_type=refresh_token&refresh_token=436761f1-2f26-412b-ab0f-bbf2cd7459c4"

【问题讨论】:

无关注释:您应该将访问令牌放在标头中(作为 URI 查询参数不安全)。 另一个无关的评论:你不需要令牌密钥端点,所以不要触摸它;并且检查令牌端点不应在生产服务器中使用permitAll() 公开(尝试isAuthenticated())。 有点相关的评论(因为它使问题产生误导)你在这里没有做任何 SSO。它是经典的身份验证/资源服务器,在资源服务器中具有基于令牌的安全性。 我认为授权码的curl命令错误(复制粘贴错误)? 可能是clientID、clientSecret或者code不同。我可以使用 curl(更改 clientID、clientSecret 和代码) 【参考方案1】:

The OAuth2 Spec 有一个关于刷新访问令牌的部分。它在 Spring OAuth 中以非常标准的方式实现(您只需将刷新令牌发布到 /token 端点)。

顺便说一句,对于 SSO,您通常不需要资源服务器。但这是一个不同的问题。

【讨论】:

没问题。乐意效劳。如果我的回答有帮助,请接受,这样其他人就会知道它可能对他们有帮助。 对不起,我也是 Oauth2 的初学者。在 Ouath2 规范中说“授权服务器可以发出新的刷新令牌”,Spring Security Oauth2 如何给出问题?我可以通过refreshtoken请求获取新的accesstoken,但是我只知道accesstoken在访问某些资源时过期了。仅供参考,我的 SSO 将授权和资源服务器分开,因为在此之前我有多个资源服务器,所以我认为我可以将授权服务器与我的资源分开。 如果您启用它们,Spring Auth Server 会发出刷新令牌(它可能不是默认设置,我忘记了)。当颁发访问令牌时,客户端大约知道它何时到期,因此它可以使用该信息或等待 401。 我只是启用了刷新令牌。我想等待 401,然后我可以调用该过程以使用刷新令牌请求新的访问令牌。但是不知道怎么做401处理程序? 如果你使用OAuth2RestTemplate,它应该是自动的。否则我想看看源代码并复制模式。

以上是关于Spring Security Oauth2:处理过期 AccessToken 的流程的主要内容,如果未能解决你的问题,请参考以下文章

spring security oauth2 认证端异常处理(基于前后分离统一返回json)

Spring Security 实战内容:OAuth2授权回调的处理机制

Spring Security Oauth2:处理过期 AccessToken 的流程

Spring Security OAuth2 授权服务器 /oauth/token - 500 处理程序没有适配器

使用 Spring Security OAuth2 和 Okta 处理基于 url 的 RBAC

Spring Security OAuth2何时检查访问令牌到期?