聊聊 OAuth 2.0 的 Token 续期处理

简介: Token 校验逻辑 // CheckTokenEndpoint.checkToken @RequestMapping(value = "/oauth/check_token") @ResponseBody public Map checkToken(@RequestPara.

Token 校验逻辑

// CheckTokenEndpoint.checkToken
@RequestMapping(value = "/oauth/check_token")
@ResponseBody
public Map<String, ?> checkToken(@RequestParam("token") String value) {
    
    // 根据 token 查询保存在 tokenStore 的令牌全部信息
    OAuth2AccessToken token = resourceServerTokenServices.readAccessToken(value);
    if (token == null) {
        throw new InvalidTokenException("Token was not recognised");
    }

    if (token.isExpired()) {
        throw new InvalidTokenException("Token has expired");
    }
    
    // 根据 token 查询保存的 认证信息 还有权限角色等 (业务信息)
    OAuth2Authentication authentication = resourceServerTokenServices.loadAuthentication(token.getValue());

    return accessTokenConverter.convertAccessToken(token, authentication);
}
    1. 当客户端带着 header token 访问 oauth2 资源服务器,资源服务器会自动拦截 token
    1. 发送 token 到 认证服务器 校验 token 合法性
    1. 若认证服务器返回给资源服务器是token不合法,则资源服务器返回给客户端对应的信息

Token 生成逻辑

    //DefaultTokenServices.createAccessToken 代码逻辑
    public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
        
        // 根据用户信息(username),查询已下发的token 
        OAuth2AccessToken existingAccessToken = tokenStore.getAccessToken(authentication);
        OAuth2RefreshToken refreshToken = null;
        
        // 存在已下发的token
        if (existingAccessToken != null) {
            // 1. token 已经被标志过期,则删除 
            if (existingAccessToken.isExpired()) {
                if (existingAccessToken.getRefreshToken() != null) {
                    refreshToken = existingAccessToken.getRefreshToken();
                    tokenStore.removeRefreshToken(refreshToken);
                }
                tokenStore.removeAccessToken(existingAccessToken);
            }
            else {
                // 直接返回存在的 token,并保存一下token 和 用户信息的关系 (username)
                tokenStore.storeAccessToken(existingAccessToken, authentication);
                return existingAccessToken;
            }
        }

        // 不存在则创建新的 token
        OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
        tokenStore.storeAccessToken(accessToken, authentication);
        // In case it was modified
        refreshToken = accessToken.getRefreshToken();
        if (refreshToken != null) {
            tokenStore.storeRefreshToken(refreshToken, authentication);
        }
        return accessToken;

    }
    1. 当我们通过oauth2 去获取 token 时,若当前用户已经存在对应的token,直接返回而不不会创建新 token。
    1. 这就意味着,虽然设置了对应客户端获取 token 的有效时间,这里获取到的token
      若是已下发旧token,有效时间不会和session 机制一样自动续期。
    1. 综上情况,在操作过程中token 过期是一个常态化的问题。

Token 刷新逻辑

curl --location --request POST 'http://auth-server/oauth/token?grant_type=refresh_token' \
--header 'Authorization: Basic dGVzdDp0ZXN0' \
--header 'VERSION: dev' \
--data-urlencode 'scope=server' \
--data-urlencode 'refresh_token=eccda61e-0c68-43af-8f67-6302cb389612'

若上,当 前端拿着正确的(未过期且未使用过)refresh_token 去调用 认证中心的刷新 端点刷新时,会 触发RefreshTokenGranter, 返回新的 Token

public class RefreshTokenGranter extends AbstractTokenGranter {
    
    @Override
    protected OAuth2AccessToken getAccessToken(ClientDetails client, TokenRequest tokenRequest) {
        String refreshToken = tokenRequest.getRequestParameters().get("refresh_token");
        return getTokenServices().refreshAccessToken(refreshToken, tokenRequest);
    }
    
}
  • refreshAccessToken 代码实现,调用 tokenStore 生成新的token
@Transactional(noRollbackFor={InvalidTokenException.class, InvalidGrantException.class})
    public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenRequest tokenRequest)
            throws AuthenticationException {

    
       createRefreshedAuthentication(authentication, tokenRequest);

        if (!reuseRefreshToken) {
            tokenStore.removeRefreshToken(refreshToken);
            refreshToken = createRefreshToken(authentication);
        }

        OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
        tokenStore.storeAccessToken(accessToken, authentication);
        if (!reuseRefreshToken) {
            tokenStore.storeRefreshToken(accessToken.getRefreshToken(), authentication);
        }
        return accessToken;
    }

客户端(前端)何时刷新

被动刷新

  1. 客户端携带 token 访问资源服务器资源
  2. 资源服务器拦截 token 去认证服务器 check_token
  3. 认证服务器返回 token 过期错误,资源服务器包装错误信息返回给客户端
  4. 客户端根据返回错误信息(响应码),直接调用认证服务器 refresh_token
  5. 认证服务器返回新的 token 给客户端, 然后再次发起 资源调用

被动请求的缺点是,用户当次请求会失败(返回token失败),对一些业务连贯的操作不是很友好

主动刷新

  1. 客户端存在计算逻辑,计算下发token 有效期
  2. 若token要过期之前,主动发起刷新

主动请求的缺点是,客户端占用部分计算资源来处理 token 失效问题

  // 10S检测token 有效期
  refreshToken() {
    this.refreshTime = setInterval(() => {
      const token = getStore({
        name: 'access_token',
        debug: true
      })
      if (this.validatenull(token)) {
        return
      }
      if (this.expires_in <= 1000 && !this.refreshLock) {
        this.refreshLock = true
        this.$store
          .dispatch('RefreshToken')
          .catch(() => {
            clearInterval(this.refreshTime)
          })
        this.refreshLock = false
      }
      this.$store.commit('SET_EXPIRES_IN', this.expires_in - 10)
    }, 10000)
  },

源码 基于Spring Boot 2.2、 Spring Cloud Hoxton & Alibaba、 OAuth2 的RBAC 权限管理系统

目录
相关文章
|
9月前
|
前端开发 Java 数据库连接
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
|
人工智能 安全 网络虚拟化
指南:Grok官网是什么?国内如何使用grok 3 官网AI
Grok AI 是一款非常强大的人工智能助手,不仅能够在社交媒体管理、语音助手等方面为用户提供便利,还可以极大提升工作效率。
8996 5
|
11月前
|
canal 关系型数据库 MySQL
MySQL 自动同步开源工具
本文介绍了几种开源工具用于实现 MySQL 数据库的自动同步。
|
10月前
|
人工智能 IDE 定位技术
通义灵码 AI IDE 正式上线,智能体自动写代码,首创自动记忆,工程感知全面升级
阿里云发布的通义灵码AI IDE深度适配千问3大模型,集成智能编码助手功能,支持编程智能体、工具调用、工程感知等能力。其核心亮点包括:支持最强开源模型千问3,全面集成通义灵码插件能力,自带编程智能体模式,支持长期记忆与行间建议预测(NES)。通义灵码已覆盖主流IDE,助力开发者实现高效智能编程,插件下载量超1500万,生成代码超30亿行,成为国内最受欢迎的辅助编程工具。立即体验更智能的开发流程!
2906 1
|
存储 人工智能 API
AgentScope:阿里开源多智能体低代码开发平台,支持一键导出源码、多种模型API和本地模型部署
AgentScope是阿里巴巴集团开源的多智能体开发平台,旨在帮助开发者轻松构建和部署多智能体应用。该平台提供分布式支持,内置多种模型API和本地模型部署选项,支持多模态数据处理。
11453 78
AgentScope:阿里开源多智能体低代码开发平台,支持一键导出源码、多种模型API和本地模型部署
|
消息中间件 JSON Java
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
34677 1
|
Java Apache Maven
【异常解决】Handler dispatch failed;nested exception is java.lang.NoClassDefFoundError: org/apache/common
【异常解决】Handler dispatch failed;nested exception is java.lang.NoClassDefFoundError: org/apache/common
11094 0
|
Ubuntu Linux 网络安全
Docker&Docker Compose安装(离线+在线)
Docker&Docker Compose安装(离线+在线)
23281 1
|
存储 人工智能 自然语言处理
大模型时代还需要知识图谱么?新一代知识图谱语义框架SPG赋能企业数智化转型
本文以商家经营和风险防控为例,介绍了在企业数字化中的图谱应用。结合当前产业应用和研究进展,本文梳理总结了LLM、KG 在企业数字化中的可能应用。
大模型时代还需要知识图谱么?新一代知识图谱语义框架SPG赋能企业数智化转型
|
设计模式 前端开发 Java
从Langchain到ReAct,在大模型时代下全新的应用开发核心
什么是ReAct框架关于什么是langchain,在使用langchain的过程中,大模型给人留下最深刻的印象无疑是Agent功能。大模型会自己分析问题,选择合适的工具,最终解决问题。这个功能背后的原理就是来自ReAct框架。ReA
22029 2
从Langchain到ReAct,在大模型时代下全新的应用开发核心

热门文章

最新文章

下一篇
开通oss服务