前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring OAuth2 实现始终获取新的令牌

Spring OAuth2 实现始终获取新的令牌

作者头像
恒宇少年
发布2021-04-25 14:35:52
2K0
发布2021-04-25 14:35:52
举报

Spring基于OAuth2协议编写的spring-oauth2实现,是行业级的接口资源安全解决方案,我们可以基于该依赖配置不同客户端的不同权限来访问接口数据。

推荐阅读

默认令牌生成方式

每当我们获取请求令牌(access_token)时,默认情况返回第一次生成的令牌,使用同一个用户多次获取令牌时,只有过期时间在缩短,其它的内容不变。

这种方式有利有弊,如果同一个账户只能有一个人登录,这样是没有任何问题的,但是如果同一个账号可以让多个人同时登录,那么就会存在一定的问题。

比如我们现在有一个名为hengboy的账户:第一个人登录时令牌有效期为我们配置的最长有效期(假设为7200秒),这时又有第二个人登录的同一个用户,第二个人获取的令牌并不会重置有效期(可能还剩下3000秒),对于这种结果并不是我们期望的

原因分析

目前spring-oauth2依赖内集成了三种存储令牌的方式,分别是:InMemoryTokenStore(内存方式)RedisTokenStore(Redis方式)JdbcTokenStore(数据库方式)

从阅读源码中可以发现无论我们配置使用什么方式来进行存储令牌,同一个账户的有效令牌只会存在一个,结合上面的场景来思考所以第二个人获取的令牌与第一个人是同一个。

DefaultTokenServices

DefaultTokenServices令牌服务是AuthorizationServerTokenServices接口的默认实现,位于org.springframework.security.oauth2.provider.token包内,提供了默认的操作令牌的方法,常用的有:

  • createAccessToken:根据客户端信息、登录用户信息来创建请求令牌(access_token)以及刷新令牌(refresh_token
  • refreshAccessToken:根据刷新令牌(refresh_token)来获取一个全新的请求令牌(access_token
  • revokeToken:撤销令牌,删除用户生成的请求令牌(access_token)、刷新令牌(refresh_token

源码解析:生成令牌

DefaultTokenServices#createAccessToken:

在创建令牌的源码方法中,首先根据认证信息去读取存储介质(TokenStore实现类)内该账户的令牌,如果令牌已经存储并且并未过期,则直接返回(这也就是同一个账户不同人登录时返回同一个令牌的逻辑),如果令牌已经过期,则删除刷新令牌(refresh_token)、请求令牌(access_token)后重新生成。

源码解析:刷新令牌

DefaultTokenServices#refreshAccessToken:

在刷新令牌的源码方法中,首先需要读取刷新令牌(refresh_token)的具体内容,如果不存在则直接抛出刷新令牌无效的异常InvalidGrantException

执行令牌刷新之前,需要根据刷新令牌删除请求令牌removeAccessTokenUsingRefreshToken,删除后再次判定刷新令牌是否失效,如果失效抛出InvalidTokenException异常。

刷新令牌的重复使用是根据全局变量reuseRefreshToken来判定的,默认情况下该变量的值为true,也就是刷新令牌可以重复使用,但是经过createAccessToken > TokenEnhancer#enhance处理后刷新令牌会被重新创建并替换(这个地方貌似是一个Bug)。

重写TokenServices

期望效果

假设请求令牌(access_token)的有效期为7200秒,也就是2个小时,刷新令牌(refresh_token)的有效期为43200秒,也就是12个小时。

在第一次通过createAccessToken获取令牌后,每次请求令牌(access_token)过期后通过刷新的方式(/oauth/token?grant_type=refresh_token)重新获取一次新的(有效期为2个小时)请求令牌,当刷新令牌(refresh_token)失效后,再次通过createAccessToken方法来获取令牌。

分析期望效果

针对上面的期望效果我们需要修改createAccessTokenrefreshAccessToken两个方法的源码,调用createAccessToken方法时不再判定是否使用已经存在的有效令牌,而调用refreshAccessToken方法时需要删除响应的refresh_token的返回字段并把新的请求令牌与刷新令牌进行绑定。

OverrideTokenServices

复制DefaultTokenServices类内的全部代码,创建一个名为OverrideTokenServices的类,为了兼容原来的逻辑,需要添加一个全局变量alwaysCreateToken,用于判定是否始终创建令牌。

重写创建令牌逻辑

如果我们想使用原来的逻辑,在初始化OverrideTokenServices类时需要设置alwaysCreateToken变量的值为false

重写刷新令牌逻辑

DefaultTokenServices类中默认定义了全局变量reuseRefreshToken,该变量的值为true,表示默认情况下刷新令牌(refresh_token)是可以重复使用的,一般刷新令牌的过期时间都比较久,当请求令牌(access_token)失效后根据刷新令牌进行获取新的有效请求令牌。

配置TokenServices

我们需要在AuthorizationServerConfigurerAdapter实现类内进行配置TokenServices的替换使用,如下所示:

测试

获取令牌示例:

可以看到上面使用同一个账号获取了两次令牌,而这两次的令牌内容是完全不同的,这也就是实现了针对同一个账号不同人登录时返回新的令牌的需求。

刷新令牌示例:

同一个账户,上面虽然刷新了两次,但是令牌的有效期不会相互影响,第一次刷新使用的是第一次获取的刷新令牌,这样其实也就是刷新的第一次的请求令牌,与第二次的无关!!!

代码示例

如果您喜欢本篇文章请为源码仓库点个Star,谢谢!!! 本篇文章示例源码可以通过以下途径获取,目录为oauth2-always-create-token

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 推荐阅读
  • 默认令牌生成方式
    • 原因分析
      • DefaultTokenServices
        • 源码解析:生成令牌
          • 源码解析:刷新令牌
          • 重写TokenServices
            • 期望效果
              • 分析期望效果
                • OverrideTokenServices
                  • 重写创建令牌逻辑
                    • 重写刷新令牌逻辑
                    • 配置TokenServices
                    • 测试
                    • 代码示例
                    相关产品与服务
                    云数据库 Redis
                    腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档