尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Sa-Token OAuth2 注解鉴权实战:@SaCheckAccessToken、@SaCheckClientToken、@SaCheckClientIdSecret 使用与原理
Sa-Token OAuth2 注解鉴权实战SaCheckAccessToken、SaCheckClientToken、SaCheckClientIdSecret 使用与原理【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架让鉴权变得简单、优雅—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-Token导读本文聚焦 Sa-Token 的sa-token-oauth2模块为资源服务器API 端提供的三枚声明式鉴权注解SaCheckAccessToken、SaCheckClientToken、SaCheckClientIdSecret。通过它们你可以在 OAuth2.0 授权服务器中零侵入地为受保护接口声明「必须携带有效 token」或「必须携带指定 scope」等校验规则将鉴权逻辑与业务逻辑彻底分离。读完本文你将掌握三个注解的完整用法、token 从请求参数与请求头中读取的具体规则以及它们底层的处理器链与错误码体系并能在自己的 OAuth2 服务端直接落地使用。一、三个注解一览sa-token-oauth2模块在cn.dev33.satoken.oauth2.annotation包下扩展了三个用于相关数据校验的注解注解校验内容可配置项SaCheckAccessToken请求中必须包含有效的access_token并且包含指定的scopescope()需要校验的 scope 数组SaCheckClientToken请求中必须包含有效的client_token并且包含指定的scopescope()需要校验的 scope 数组SaCheckClientIdSecret请求中必须包含有效的client_id和client_secret信息无三个注解的源码定义位于 sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/annotation/SaCheckAccessToken与SaCheckClientToken均声明了一个String[] scope() default {}属性用于声明需要校验的 scope 列表三者都使用Retention(RUNTIME)Target({METHOD, TYPE})既可以标注在方法上也可以标注在类上——标注在类上时效果等同于标注在该类的所有方法上三个注解均自1.39.0版本起提供。与 Sa-Token 核心sa-token-core的注解鉴权规则一致当你需要同时校验多个 scope 时注解默认是and且关系——即所声明的 scope 必须全部具备才能放行具体校验逻辑可参考下文「五、scope 校验的底层实现」。二、使用前提注册拦截器 / 插件和 Sa-Token-Core 模块的SaCheckLogin、SaCheckPermission等注解一样你必须先注册框架的内置拦截器才可以使用 OAuth2 这三个注解。这是因为注解鉴权功能由 Sa-Token 的全局拦截器统一扫描并触发而拦截器默认处于关闭状态避免为项目带来不必要的性能负担。方式一注册全局拦截器在你的 Web MVC 配置类中注册SaInterceptorConfiguration public class SaTokenConfigure implements WebMvcConfigurer { // 注册 Sa-Token 拦截器打开注解式鉴权功能 Override public void addInterceptors(InterceptorRegistry registry) { // 注册 Sa-Token 拦截器打开注解式鉴权功能 registry.addInterceptor(new SaInterceptor()).addPathPatterns(/**); } }详细说明参考文档注解鉴权。方式二通过插件安装OAuth2 注解的自动注册在 Sa-Token 1.41.0 及以后版本中sa-token-oauth2还提供了插件机制SaTokenPluginForOAuth2.java其install()方法会向全局注解策略注册三个注解处理器public class SaTokenPluginForOAuth2 implements SaTokenPlugin { Override public void install() { // 安装 OAuth2 鉴权注解 SaAnnotationStrategy.instance.registerAnnotationHandler(new SaCheckAccessTokenHandler()); SaAnnotationStrategy.instance.registerAnnotationHandler(new SaCheckClientTokenHandler()); SaAnnotationStrategy.instance.registerAnnotationHandler(new SaCheckClientIdSecretHandler()); } }这意味着三个 OAuth2 注解的校验逻辑是通过SaAnnotationStrategy注解策略机制挂载进框架的——注册完成后拦截器扫描到对应注解时就会自动分发到各自的 Handler 执行校验。注意无论采用哪种方式最终都必须存在 Sa-Token 的全局拦截器SaInterceptor否则注解不会被触发执行。三、SaCheckAccessToken校验 Access TokenSaCheckAccessToken用于保护代表资源所有者用户授权的接口——请求中必须携带一个有效的access_token且该 token 具备指定的 scope。3.1 完整示例RestController RequestMapping(/test) public class TestController { // 测试携带有效的 access_token 才可以进入请求 // 你可以在请求参数中携带 access_token 参数或者从请求头以 Authorization: bearer xxx 的形式携带 SaCheckAccessToken RequestMapping(/checkAccessToken) public SaResult checkAccessToken() { return SaResult.ok(访问成功); } // 测试携带有效的 access_token 并且具备指定 scope 才可以进入请求 SaCheckAccessToken(scope userinfo) RequestMapping(/checkAccessTokenScope) public SaResult checkAccessTokenScope() { return SaResult.ok(访问成功); } // 测试携带有效的 access_token 并且具备指定 scope 列表才可以进入请求 SaCheckAccessToken(scope {openid, userinfo}) RequestMapping(/checkAccessTokenScopeList) public SaResult checkAccessTokenScopeList() { return SaResult.ok(访问成功); } }该示例同时也完整存在于 sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-server/src/main/java/com/pj/test/TestController.java你可以直接运行该 demo 项目进行验证。3.2 token 的两种携带方式从源码 SaOAuth2DataResolverDefaultImpl.readAccessToken() 可以看出框架读取access_token遵循固定的优先级顺序请求参数优先读取名为access_token的请求参数Query 参数或 Form 参数均可有值则直接采用请求头若请求参数中没有则读取Authorization请求头且必须严格以Bearer注意 B 大写、后有空格为前缀框架会裁剪前缀后取剩余部分作为 token 值两种方式都取不到时返回null后续校验将抛「无效 access_token」异常。即下面的两种请求等价GET /test/checkAccessToken?access_tokenxxxx GET /test/checkAccessToken Authorization: Bearer xxxx3.3 注解处理器与校验链路SaCheckAccessToken的处理器为 SaCheckAccessTokenHandler.javapublic static void _checkMethod(String[] scope) { String accessToken SaOAuth2Manager.getDataResolver().readAccessToken(SaHolder.getRequest()); SaOAuth2Manager.getTemplate().checkAccessTokenScope(accessToken, scope); }其核心校验在SaOAuth2Template.checkAccessTokenScope()SaOAuth2Template.java通过SaOAuth2Manager.getDao().getAccessToken(accessToken)查询 token查不到则抛出SaOAuth2AccessTokenException错误码30106无效 access_token若注解未声明任何 scopescope为空数组直接放行即只做「token 有效性」校验若声明了 scope则逐一检查 token 的scopes集合是否包含每个 scope任一缺失即抛出SaOAuth2AccessTokenScopeException错误码30108Access-Token 不具备指定的 Scope。四、SaCheckClientToken校验 Client TokenSaCheckClientToken用于保护代表第三方应用客户端自身授权的接口——请求中必须携带一个有效的client_token且该 token 具备指定的 scope。它校验的是「应用身份」而非「用户身份」常用于凭证式Client Credentials授权模式下的应用级接口。4.1 完整示例RestController RequestMapping(/test) public class TestController { // 测试携带有效的 client_token 才可以进入请求 // 你可以在请求参数中携带 client_token 参数或者从请求头以 Authorization: bearer xxx 的形式携带 SaCheckClientToken RequestMapping(/checkClientToken) public SaResult checkClientToken() { return SaResult.ok(访问成功); } // 测试携带有效的 client_token 并且具备指定 scope 才可以进入请求 SaCheckClientToken(scope userinfo) RequestMapping(/checkClientTokenScope) public SaResult checkClientTokenScope() { return SaResult.ok(访问成功); } // 测试携带有效的 client_token 并且具备指定 scope 列表才可以进入请求 SaCheckClientToken(scope {openid, userinfo}) RequestMapping(/checkClientTokenScopeList) public SaResult checkClientTokenScopeList() { return SaResult.ok(访问成功); } }4.2 token 的两种携带方式与 Access Token 的读取规则完全对称见 SaOAuth2DataResolverDefaultImpl.readClientToken()优先读取名为client_token的请求参数否则读取Authorization请求头中Bearer前缀之后的内容都取不到则返回null。GET /test/checkClientToken?client_tokenxxxx GET /test/checkClientToken Authorization: Bearer xxxx4.3 注解处理器与校验链路处理器 SaCheckClientTokenHandler.java 调用SaOAuth2Template.checkClientTokenScope()SaOAuth2Template.java通过getClientToken(clientToken)查询 token无效则抛出SaOAuth2ClientTokenException错误码30107无效 client_tokenscope 为空时仅校验有效性逐个校验 scope任一缺失抛出SaOAuth2ClientTokenScopeException错误码30109Client-Token 不具备指定的 Scope。五、scope 校验的底层实现从上面的源码可以看出Access Token 与 Client Token 的 scope 校验逻辑高度一致都是「先验 token 有效性再验 scope 归属」。以checkAccessTokenScope为例其校验语义为token 必须存在于 OAuth2 数据层默认基于 Sa-Token 数据持久层实现见 SaOAuth2Dao.java 中的saveAccessToken/getAccessToken、saveClientToken/getClientTokenscope属性声明的每一项都必须出现在 token 的scopes集合中全部满足才放行缺一不可and 关系。此外SaOAuth2Template还提供了配套的布尔判断方法便于你在代码中做更灵活的控制boolean hasAccessTokenScope(String accessToken, String... scopes)判断 Access Token 是否具备指定 scope返回true/false内部以捕获SaOAuth2AccessTokenException的方式返回布尔值见 SaOAuth2Template.javaboolean hasClientTokenScope(String clientToken, String... scopes)对 Client Token 的等价判断SaOAuth2Template.java。六、SaCheckClientIdSecret校验应用凭证SaCheckClientIdSecret用于验证调用方是不是一个合法的第三方应用——请求中必须携带正确的client_id与client_secret信息校验通过后即代表该应用身份合法。6.1 完整示例RestController RequestMapping(/test) public class TestController { // 测试携带有效的 client_id 和 client_secret 信息才可以进入请求 // 你可以在请求参数中携带 client_id 和 client_secret 参数或者从请求头以 Authorization: Basic base64(client_id:client_secret) 的形式携带 SaCheckClientIdSecret RequestMapping(/checkClientIdSecret) public SaResult checkClientIdSecret() { return SaResult.ok(访问成功); } }6.2 凭证的两种携带方式凭证读取逻辑位于 SaOAuth2DataResolverDefaultImpl.readClientIdAndSecret()请求参数优先读取名为client_id与client_secret的请求参数必须两者都有值才采用源码注释特别标注了这一点Authorization Basic 请求头若参数不满足则尝试从Authorization头中按Basic base64(client_id:client_secret)格式解码出两者——即把client_id:client_secret拼接后做 Base64 编码放进请求头若只提供了client_id也会构建一个clientSecret为空的凭证对象交由后续校验判断此时 secret 校验必然失败若两者均未提供则直接抛出SaOAuth2Exception错误码30191其它异常提示「请提供 client 信息」。POST /test/checkClientIdSecret Content-Type: application/x-www-form-urlencoded client_id1001client_secretxxxx # 或使用请求头xxxx 为 base64(client_id:client_secret) 的值 Authorization: Basic xxxx6.3 注解处理器与校验链路处理器 SaCheckClientIdSecretHandler.java 调用了SaOAuth2ServerProcessor.checkCurrClientSecret()SaOAuth2ServerProcessor.java后者依次执行通过数据解析器readClientIdAndSecret从当前请求读取凭证调用SaOAuth2Template.checkClientSecret(clientId, clientSecret)SaOAuth2Template.java完成校验先按clientId查SaClientModel应用模型查不到抛出SaOAuth2ClientModelException错误码30105无效 client_id再比对clientSecret不一致抛出SaOAuth2ClientModelException错误码30115无效 client_secret全部通过则返回SaClientModel对象。七、错误码速查表三个注解校验失败时抛出的异常均带有统一的 OAuth2 错误码定义于 SaOAuth2ErrorCode.java便于你在全局异常处理器中精准捕获与返回错误码含义触发注解30105无效 client_idSaCheckClientIdSecret30106无效 access_tokenSaCheckAccessToken30107无效 client_tokenSaCheckClientToken30108Access-Token 不具备指定的 ScopeSaCheckAccessToken(scope...)30109Client-Token 不具备指定的 ScopeSaCheckClientToken(scope...)30115无效 client_secretSaCheckClientIdSecret30191其它异常如未提供 client 信息SaCheckClientIdSecret对应的异常类集中在cn.dev33.satoken.oauth2.exception包下例如SaOAuth2AccessTokenException、SaOAuth2AccessTokenScopeException、SaOAuth2ClientModelException、SaOAuth2ClientTokenException等它们都继承了统一的SaOAuth2Exception基类可通过e.getCode()获取错误码。八、测试用例与可运行 Demo8.1 单元测试sa-token-oauth2模块为三个注解处理器提供了完整的单元测试覆盖「有效 token 放行、缺 token 抛异常、scope 不匹配抛异常」等典型场景SaCheckAccessTokenHandlerTest.java验证携带有效 access_token 且 scope 匹配时放行token 缺失时抛异常token 有效但缺指定 scope如声明userinfo却请求admin时抛30108SaCheckClientTokenHandlerTest.java对应 Client Token 的同类场景缺失抛30107、scope 不匹配抛30109SaCheckClientIdSecretHandlerTest.java验证 client_id/client_secret 的校验逻辑。8.2 可运行 Demo官方 demo 项目 sa-token-demo-oauth2-server 中的 TestController.java 完整演示了本文三个注解的七种用法无 scope / 单 scope / scope 列表启动服务后可通过对应路由直接联调验证。九、三个注解的选择建议在实际的 OAuth2 资源服务器中三枚注解各自服务不同的安全语义建议按如下场景选用接口返回用户私有数据需要知道「哪个用户」在调用→ 使用SaCheckAccessToken必要时通过 scope 细分权限接口仅面向已签约的第三方应用开放与具体用户无关如应用调用凭证式接口→ 使用SaCheckClientToken接口需要先确认调用方应用身份如 token 签发类接口、管理类接口→ 使用SaCheckClientIdSecret需要同时校验「应用身份 用户身份」时可将SaCheckClientIdSecret与SaCheckAccessToken叠加在同一方法上——多个注解共存时必须全部通过校验才能进入方法。十、小结SaCheckAccessToken、SaCheckClientToken、SaCheckClientIdSecret三枚注解让 OAuth2 授权服务器的接口鉴权变得和普通登录鉴权一样简单只需在 Controller 方法或类上声明注解框架即会在全局拦截器中自动完成 token 有效性、scope 归属与应用凭证的校验。通过本文结合源码的解析你可以看到它们背后由「注解策略注册 → 数据解析器读取凭证 → Template 模板校验」三层结构支撑错误码与异常体系完备并有单元测试与可运行 demo 佐证可以放心在生产项目中落地使用。【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架让鉴权变得简单、优雅—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-Token创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

光纤价格波动底层逻辑:从光棒到集采的全链路拆解

光纤价格波动底层逻辑:从光棒到集采的全链路拆解

提到“光纤价格”这四个字,不同人的反应完全不一样。家里装宽带的用户觉得无所谓,反正每月套餐一直在降;搞通信工程的朋友却把这几个字当成晴雨表——项目报价、材料囤货、利润空间,全都系在这条玻璃丝的行情上。我从做交付开始就…

📅 2026/9/14 1:50:31
uni-app购车车小程序源码解析:从工程结构到微信小程序上线实践

uni-app购车车小程序源码解析:从工程结构到微信小程序上线实践

简介:一份基于uni-app框架开发的购车车小程序完整源码包,面向想快速上手小程序跨平台开发、或需要汽车销售业务参考的开发者。项目采用Vue语法构建,覆盖车辆展示、分类、购物车、个人中心等典型页面,并通过uni-app统一接口适配微信…

📅 2026/9/14 1:45:31
基于Spring Boot与MyBatis的景区旅游管理系统构建指南

基于Spring Boot与MyBatis的景区旅游管理系统构建指南

简介:基于 Java、Springboot、Mybatis、MySQL、Bootstrap、Maven 构建的景区旅游管理系统项目包,面向 Java 全栈学习者、毕业设计者及旅游信息化开发人员,覆盖用户、景区、订单、支付、评论、地图等典型业务,既可用于课程设计&…

📅 2026/9/14 1:45:31
MORE NEWS

更多资讯

📰

从公式到代码:手写DFT彻底搞懂FFT与频谱分析

1. 从公式到代码:DFT到底在算什么搞信号处理的人,十有八九都经历过这样一个阶段:教材翻到离散傅里叶变换那一章,公式看了无数遍,笔记抄了厚厚一摞,考试也能拿高分,但一问到"DFT的代码到底怎…

📰

Automatisch Disqus 集成:New Comments 与 New Flagged Comments 触发器的配置与实现原理

Automatisch Disqus 集成:New Comments 与 New Flagged Comments 触发器的配置与实现原理 【免费下载链接】automatisch The open source Zapier alternative. Build workflow automation without spending time and money. 项目地址: https://gitcode.com/GitHub…

📰

Kali Linux 安装全攻略:虚拟机与物理机实战指南

装 Kali Linux 这事情,看着教程一大堆,真正能一次走通的不多。我这些年折腾过 VMware、VirtualBox、Hyper-V,也在老笔记本上直接物理机装过,前前后后刷了不下几十次。说实话,安装本身并不复杂,但很多人卡在…

📰

用 GitHub Actions 自动发布 Scalar Docs 项目:基于 @scalar/cli 的 CI 发布实践

用 GitHub Actions 自动发布 Scalar Docs 项目:基于 scalar/cli 的 CI 发布实践 【免费下载链接】scalar Scalar is an open-source API platform:                                       🌐 Modern REST API C…

📰

Nginx配置前后端分离项目实战指南

1. 为什么需要Nginx配置前后端服务现代Web应用开发中,前后端分离架构已成为主流模式。这种架构下,前端通常使用React、Vue等框架构建单页应用(SPA),后端则提供RESTful API接口。Nginx作为高性能的Web服务器和反向代理,在这种架构中…

📰

超外差接收机本振泄露原理与SDR探测定位实战指南

做无线电监测和软件定义无线电(SDR)这么多年,我一直觉得有一个现象特别有意思:一台明明只负责“收”信号的设备,居然也能被外面的人发现,甚至被定位。很多人天然的认知是,只要我不发射、不主动“…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬