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

public OAuth2Authentication loadAuthentication(String accessTokenValue) throws AuthenticationException,

            InvalidTokenException {

        OAuth2AccessToken accessToken = tokenStore.readAccessToken(accessTokenValue);

        if (accessToken == null) {

            throw new InvalidTokenException("Invalid access token: " + accessTokenValue);

        }

        else if (accessToken.isExpired()) {

            // 失效后accessToken即被删除

            tokenStore.removeAccessToken(accessToken);

            throw new InvalidTokenException("Access token expired: " + accessTokenValue);

        }

 

        // 忽略部分代码

        return result;

    }

  

可以看到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

public class OauthJwtAccessTokenConverter extends JwtAccessTokenConverter {

    private JsonParser objectMapper = JsonParserFactory.create();

 

    public OauthJwtAccessTokenConverter(SecurityUserService userService) {

        // 使用SecurityContextHolder.getContext().getAuthentication()能获取到User信息

        super.setAccessTokenConverter(new OauthAccessTokenConverter(userService));

    }

 

    @Override

    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {

        DefaultOAuth2AccessToken result = new DefaultOAuth2AccessToken(accessToken);

        Map<String, Object> info = new LinkedHashMap<String, Object>(accessToken.getAdditionalInformation());

        String tokenId = result.getValue();

        if (!info.containsKey(TOKEN_ID)) {

            info.put(TOKEN_ID, tokenId);

        else {

            tokenId = (String) info.get(TOKEN_ID);

        }

 

        // access_token 包含自动刷新过期token需要的数据(client_id/secret/refresh_token)

        Map<String, Object> details = (Map<String, Object>) authentication.getUserAuthentication().getDetails();

        if (!Objects.isNull(details) && details.size() > 0) {

            info.put(OauthConstant.OAUTH_CLIENT_ID,

                    details.getOrDefault("client_id", details.get(OauthConstant.OAUTH_CLIENT_ID)));

 

            

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值