spring oauth2+JWT后端自动刷新access_token
这段时间在学习搭建基于spring boot的spring oauth2 和jwt整合。
说实话挺折腾的。使用jwt做用户鉴权,难点在于token的刷新和注销。
当然注销的难度更大,网上的一些方案也没有很出色的。这个功能基本让我放弃了jwt(滑稽笑~)。
所以今天我单纯的先记录jwt token的刷新。
Token刷新
jwt token刷新方案可以分为两种:一种是校验token前刷新,第二种是校验失败后刷新。
我们先来说说第二种方案
验证失效后,Oauth2框架会把异常信息发送到OAuth2AuthenticationEntryPoint类里处理。这时候我们可以在这里做jwt token刷新并跳转。
网上大部分方案也是这种:失效后,使用refresh_token获取新的access_token。并将新的access_token设置到response.header然后跳转,前端接收并无感更新新的access_token。
接着说第一种,其实两种方案的代码我都写过,最终使用了第一种。原因是兼容其他token刷新方案。
我在使用第二种方案并且jwt token刷新功能正常使用后,想换一种token方案做兼容。
切换成memory token的时候,发现OAuth2AuthenticationEntryPoint里面拿不到旧的token信息导致刷新失败。
我们翻一下源码
DefaultTokenServices.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
可以看到JwtTokenStore的removeAccessToken:它是一个空方法,什么也没做。所以我们在OAuth2AuthenticationEntryPoint依然能拿到旧的token并作处理。
但是其他的token策略在token过期后,被remove掉了。一点信息都没留下,巧妇难为无米之炊。所以,我之后选择选择了第一种方案,在token校验remove前做刷新处理。
jwt token刷新的方案是这样的:
客户端发送请求大部分只携带access_token,并不携带refresh_token、client_id及client_secret等信息。所以我是先把refresh_token、client_id等信息放到access_token里面。
因为jwt并不具有续期的功能,所以在判断token过期后,立刻使用refresh_token刷新。并且在response的header里面添加标识告诉前端你的token实际上已经过期了需要更新。
当然,其他的类似memory token、redis token可以延期的,更新策略就没这么复杂:直接延长过期时间并且不需要更新token。
说了这么多,放token刷新相关代码:
首先,我们需要把refresh_token、client_id、client_secret放入到access_token中,以便刷新。所以我们需要重写JwtAccessTokenConverter的enhance方法。
OauthJwtAccessTokenConverter.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
|
信息准备好了,就要开始处理刷新。就是改写DefaultTokenServices的loadAuthentication方法。
OauthTokenServices.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
类里面的TokenRefreshExecutor就是我们的重点。这个类定义了两个比较重要的接口。
shouldRefresh:是否需要刷新
refresh:刷新
TokenRefreshExecutor.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
然后我们来看看jwt刷新器,
OauthJwtTokenRefreshExecutor.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
|
类写完了,开始使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
|
然后是认证服务器相关代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
|
接着是前端处理, 用的axios。
1 2 3 4 5 6 7 8 |
|
这样就做到了jwt无感刷新。
讲完了jwt的token刷新,多嘴说说memory token的刷新。
上面讲了,memory token刷新策略比较简单,每次请求过来直接给token延期即可。
OauthTokenRefreshExecutor.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
然后修改TokenConfig相关bean注册即可。
好了,Token刷新这块差不多就这样了。Token注销暂时没有好的思路。
如果Token刷新有更好的方案可以告知,也欢迎分享Token注销方案。