新闻详情

新闻详情

首页 / 资讯中心 / 详情

Sa-Token API Key 插件详解:构建“可控式部分授权”的接口调用密钥体系

发布时间:2026/9/13 15:18:24来源:尧图网络
Sa-Token API Key 插件详解:构建“可控式部分授权”的接口调用密钥体系
Sa-Token API Key 插件详解构建“可控式部分授权”的接口调用密钥体系【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架让鉴权变得简单、优雅—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-TokenSa-Token 的 API Key 模块sa-token-apikey为开放接口提供了一种独立于会话 token 的调用凭证每个 API Key 绑定具体用户、可赋予最小化 Scope 权限、可设置有效期并随时回收。本文基于官方插件文档 api-key.md结合 sa-token-apikey 插件源码完整讲清 API Key 的适用场景、数据模型、创建与校验 API、SaCheckApiKey注解鉴权、数据库模式与多账号模式的实现原理读完即可在后端系统中落地一套第三方调用授权体系。1、什么是 API Key需求场景与凭证选型API Key应用程序编程接口密钥是一种用于身份验证和授权的字符串代码由服务提供商生成并分配给开发者或用户用于标识 API 请求的来源、确保请求合法性并控制访问权限。用一句大白话说API Key 是一种接口调用密钥类似于会话 token但具有更灵活的权限控制。1.1 典型业务场景第三方插件授权官方文档给出了一个很有代表性的场景某论坛网站发现大批账号头像能自动按日期变化调查后发现是第三方公司开发的插件在“代替用户”调用 API——而插件要求用户交出账号密码才能工作。随着时间推移越来越多第三方插件涌入其中不守规矩的插件甚至大量收集用户密码等隐私信息。公司升级系统、增加 IP 校验等风控判断后恶意插件确实被阻断了但用户对插件能力的真实需求依然存在。“堵不如疏”——既然用户有需求、第三方愿意免费开发插件那就设计一套授权架构既不需要用户把账号密码交给第三方插件又能让插件拿到有限权限来调用特定 API 为用户服务。API Key 正是为这种“可控式部分授权”而设计的身份凭证。1.2 不同凭证的对比为了让第三方插件代表用户工作用户必须提供一个“凭证”。不同凭证带来完全不同的安全后果提供的凭证后果账号密码插件得到账号所有权限安全风险极高会话 token插件可调用几乎所有 API安全风险极高且受用户退出登录导致 token 失效的影响API Key在可控范围内部分授权可随时取消授权设计得当不会造成安全问题API Key 具有以下特点格式类似于会话 token是一个随机字符串每个 API Key 都绑定具体的用户 id后端可查询到该 API Key 的授权人是谁一个用户可以创建多个 API Key用于不同的插件每个 API Key 可赋予不同的 scope 权限实现最小化授权API Key 可设置有效期并随时删除回收。2、模块结构与插件安装机制从源码结构看sa-token-apikey插件的包布局非常清晰各核心类均位于 sa-token-plugin/sa-token-apikey/src/main/java/cn/dev33/satoken/apikey 下类职责SaApiKeyUtil静态工具类业务代码最常用的入口内部全部委托给默认SaApiKeyTemplateSaApiKeyTemplateAPI Key 操作类承载创建、保存、查询、校验、索引的全部核心逻辑ApiKeyModelAPI Key 数据模型SaApiKeyConfig模块配置前缀、有效期、索引开关SaApiKeyDataLoader数据加载器接口数据库模式的核心扩展点SaCheckApiKey注解鉴权注解SaApiKeyManager全局组件管理器持有 config、dataLoader、template 单例插件的安装逻辑极简见 SaTokenPluginForApiKeypublic class SaTokenPluginForApiKey implements SaTokenPlugin { Override public void install() { // 安装 API Key 鉴权注解 SaAnnotationStrategy.instance.registerAnnotationHandler(new SaCheckApiKeyHandler()); } }即在框架启动时向注解策略注册表注册SaCheckApiKeyHandler使SaCheckApiKey注解被框架的 AOP/拦截器体系统一识别——这也是该模块无需额外编写拦截器就能实现注解鉴权的原因。3、引入依赖在使用 API Key 模块之前必须先引入依赖!-- Sa-Token 整合 API Key -- dependency groupIdcn.dev33/groupId artifactIdsa-token-apikey/artifactId version${sa.top.version}/version /dependency版本属性sa.top.version可统一管理也可直接写死具体版本号。仓库中 sa-token-bom 与 sa-token-dependencies 对插件版本做了集中管理实际引用时可参考其中的版本定义。4、ApiKeyModelAPI Key 的数据模型所有 API Key 信息都由 ApiKeyModel 承载一个模型对象可设置以下属性与文档示例一致ApiKeyModel akModel new ApiKeyModel(); akModel.setLoginId(10001); // 设置绑定的用户 id akModel.setApiKey(AK-NAO6u57zbOWCmLaiVQuVW2tyt3rHpZrXkaQp); // 设置 API Key 值 akModel.setTitle(commit); // 设置名称 akModel.setIntro(提交代码专用); // 设置描述 akModel.addScope(commit, pull); // 设置权限范围 akModel.setExpiresTime(System.currentTimeMillis() 2592000); // 设置失效时间13位时间戳-1永不失效 akModel.setIsValid(true); // 设置是否有效 akModel.addExtra(name, 张三); // 设置扩展信息 // 保存 SaApiKeyUtil.saveApiKey(akModel);结合 ApiKeyModel 源码 的字段定义各属性含义如下属性类型说明apiKeyStringAPI Key 值默认前缀AK- 36 位随机字符串loginIdObject绑定的账号 idtitle/introString名称 / 描述createTimelong创建时间13 位时间戳构造函数中自动取当前时间expiresTimelong到期时间13 位时间戳-1表示永不过期isValidBoolean是否有效true生效false禁用默认truescopesListString授权范围列表extraDataMap扩展数据通过addExtra(key, value)/getExtra(key)读写有两处源码细节值得注意一是保存前自检。checkByCanSaved() 方法会在saveApiKey前强制校验apiKey、loginId、createTime、expiresTime、isValid均不可缺失任一字段不合法即抛出码为12304的ApiKeyException。这意味着自行new ApiKeyModel()时必须补齐这些字段createTime由构造函数自动填充。二是过期时间语义。expiresTime是 13 位毫秒时间戳SaTokenDao.NEVER_EXPIRE即-1表示永不过期。模型内置 timeExpired() 判断是否超时expiresIn()计算剩余秒数并作为缓存 TTL使过期 Key 在缓存层面也会自动消失。5、创建、保存与查询 API Key5.1 快速创建// 为指定用户创建一个新的 API KeyloginId 会自动绑定 ApiKeyModel akModel SaApiKeyUtil.createApiKeyModel(10001).setTitle(test); System.out.println(API Key 值 akModel.getApiKey()); // 保存 API Key SaApiKeyUtil.saveApiKey(akModel); // 删除 API Key SaApiKeyUtil.deleteApiKey(apiKey);从 createApiKeyModel 源码 看创建过程做了三件事通过SaStrategy.instance.generateUniqueToken生成随机串并且循环检测新 Key 是否与已存在的 Key 冲突冲突则重试保证生成的 API Key 全局唯一随机值由SaApiKeyConfig的prefix默认AK-拼接 36 位随机字符串组成带上loginId参数时自动设置isValidtrue并按配置项timeout计算expiresTimetimeout -1时永久有效否则为当前时间 timeout 秒。5.2 保存的内部逻辑缓存 索引saveApiKey() 的执行流程为先执行ak.checkByCanSaved()数据自检以tokenName:apikey:apiKey为键写入 SaTokenDaoTTL 取 Key 的剩余有效期若已过期则直接删除若开启了索引记录getIsRecordIndex()为 true默认开启则在以loginId为 id 的 Raw Session 中维护一个__HD_API_KEY_LIST索引列表记录该用户名下所有 API Key并调用adjustIndex把 Session TTL 调整为名下 Key 的最大剩余有效期做到最小化内存占用。5.3 查询与删除// 获取 API Key 详细信息无效返回 null ApiKeyModel akModel SaApiKeyUtil.getApiKey(AK-NAO6u57zbOWCmLaiVQuVW2tyt3rHpZrXkaQp); // 直接获取 ApiKey 所代表的 loginId无效/过期/禁用会抛异常 Object loginId SaApiKeyUtil.getLoginIdByApiKey(AK-NAO6u57zbOWCmLaiVQuVW2tyt3rHpZrXkaQp); // 获取指定 loginId 的 ApiKey 列表记录依赖索引功能 ListApiKeyModel apiKeyList SaApiKeyUtil.getApiKeyList(10001); // 删除指定 loginId 名下的所有 ApiKey依赖索引功能 SaApiKeyUtil.deleteApiKeyByLoginId(10001);getApiKeyList与deleteApiKeyByLoginId都依赖上述索引列表实现从 源码 看若未开启索引如数据库模式下手动关闭会记录 warn 日志并返回空列表/直接跳过不会抛异常但功能不可用。此外deleteApiKey在删除 Key 后会自动同步清理索引若某用户名下最后一个 Key 被删对应的 Raw Session 也会被整体删除。5.4 模块级配置SaApiKeyConfigSaApiKeyConfig 提供三个配置项配置项默认值说明prefixAK-API Key 前缀timeout259200030 天单位秒新建 API Key 的默认有效期-1永久有效注意修改此配置不影响已创建的 KeyisRecordIndextrue框架是否记录“用户名下 Key 列表”索引配置实例由 SaApiKeyManager 以双检锁单例管理可通过SaApiKeyManager.setConfig(...)在应用初始化阶段整体替换例如// 应用启动时调整 API Key 模块配置 SaApiKeyManager.setConfig(new SaApiKeyConfig() .setPrefix(AK-) .setTimeout(2592000) .setIsRecordIndex(true));6、校验 API Key有效性与 Scope 权限6.1 基础校验 API// 校验指定 API Key 是否有效无效会抛出异常 ApiKeyException SaApiKeyUtil.checkApiKey(AK-XxxXxxXxx); // 校验指定 API Key 是否具有指定 Scope 权限AND 模式不具备会抛出 ApiKeyScopeException SaApiKeyUtil.checkApiKeyScope(AK-XxxXxxXxx, userinfo); // 校验指定 API Key 是否具有指定 Scope 权限返回 true 或 false SaApiKeyUtil.hasApiKeyScope(AK-XxxXxxXxx, userinfo); // 校验指定 API Key 是否属于指定账号 id SaApiKeyUtil.checkApiKeyLoginId(AK-XxxXxxXxx, 10001);checkApiKey() 源码 展示了完整的三级判定链任何一级不通过都会抛出携带细分错误码的ApiKeyExceptionKey 不存在缓存与数据库均查不到→ 错误码12301Key 已过期timeExpired()→ 错误码12302Key 被禁用isValid false→ 错误码12303。除文档列出的方法外SaApiKeyUtil 还提供了一组对称的布尔版本与 OR 模式方法可在不引入 try-catch 的场景使用// OR 模式具备任一 Scope 即可异常抛出版 / 布尔返回版 SaApiKeyUtil.checkApiKeyScopeOr(apiKey, userinfo, chat); boolean ok SaApiKeyUtil.hasApiKeyScopeOr(apiKey, userinfo, chat); // 布尔返回版避免捕获异常 boolean ok1 SaApiKeyUtil.hasApiKeyScope(apiKey, userinfo); boolean ok2 SaApiKeyUtil.isApiKeyLoginId(apiKey, 10001);AND 模式要求 Key 具备全部 ScopeOR 模式具备其一即可这与SaCheckApiKey注解的mode属性语义一致。6.2 异常与错误码模块定义了两个异常类ApiKeyException继承自 Sa-Token 核心异常SaTokenException额外携带引发异常的apiKey值与 ApiKeyScopeExceptionScope 校验失败的细分异常。细分错误码定义在 SaApiKeyErrorCode错误码含义12301无效 API Key12302API Key 已过期12303API Key 已被禁用12304API Key 字段自检未通过保存前校验12305未开启索引记录功能却调用了相关 API12311API Key 不具有指定 Scope12312API Key 不属于指定用户实际项目中可在全局异常处理器中捕获ApiKeyException并按错误码返回统一 JSON便于前端或第三方调用方区分“Key 无效”“已过期”“被禁用”“权限不足”等不同拒绝原因。7、注解鉴权SaCheckApiKeySaCheckApiKey可标注在方法或类上标注在类上等同于标注该类所有方法属性定义见 SaCheckApiKey 源码scopeString 数组指定 API Key 必须包含的权限范围modeSaMode.AND默认或SaMode.OR多 Scope 时的校验模式。完整的注解鉴权示例继承自官方文档/** * API Key 资源 相关接口 */ RestController public class ApiKeyResourcesController { // 必须携带有效的 ApiKey 才能访问 SaCheckApiKey RequestMapping(/akRes1) public SaResult akRes1() { ApiKeyModel akModel SaApiKeyUtil.currentApiKey(); System.out.println(当前 ApiKey: akModel); return SaResult.ok(调用成功); } // 必须携带有效的 ApiKey 且具有 userinfo 权限 SaCheckApiKey(scope userinfo) RequestMapping(/akRes2) public SaResult akRes2() { ApiKeyModel akModel SaApiKeyUtil.currentApiKey(); System.out.println(当前 ApiKey: akModel); return SaResult.ok(调用成功); } // 必须携带有效的 ApiKey 且同时具有 userinfo、chat 权限 SaCheckApiKey(scope {userinfo, chat}) RequestMapping(/akRes3) public SaResult akRes3() { ApiKeyModel akModel SaApiKeyUtil.currentApiKey(); System.out.println(当前 ApiKey: akModel); return SaResult.ok(调用成功); } // 必须携带有效的 ApiKey 且具有 userinfo、chat 其中之一权限 SaCheckApiKey(scope {userinfo, chat}, mode SaMode.OR) RequestMapping(/akRes4) public SaResult akRes4() { ApiKeyModel akModel SaApiKeyUtil.currentApiKey(); System.out.println(当前 ApiKey: akModel); return SaResult.ok(调用成功); } }注解的处理逻辑在 SaCheckApiKeyHandler 中先从当前请求读取 API KeySaApiKeyUtil.readApiKeyValue(SaHolder.getRequest())再按mode分别调用checkApiKeyScopeAND或checkApiKeyScopeOrOR。注意处理器在读取到空 Key 时同样会走 Scope 校验并抛出异常因此未携带 API Key 的请求会被明确拒绝。在业务方法内还可用SaApiKeyUtil.currentApiKey()从当前请求中读取并校验 API Key返回完整的ApiKeyModel含 loginId、scopes、extraData 等便于日志审计或按授权人做业务分支。8、前端如何提交 API Key默认情况下前端可以从任意途径提交 API Key 字符串只要后端代码里能直接拿到并手动调用校验方法即可。但如果后端是通过SaApiKeyUtil.currentApiKey()方法获取或使用SaCheckApiKey注解校验则前端必须按约定格式提交。从 readApiKeyValue 源码 看框架按以下优先级依次尝试读取请求参数参数名为命名空间值默认命名空间是apikey全小写即/user/getInfo?apikeyAK-NAO6u57zbOWCmLaiVQuVW2tyt3rHpZrXkaQp请求头头名同样是命名空间值如apikey: AK-XxxBasic 认证Authorization 头通过SaHttpBasicUtil.getAuthorizationValue()解析用户名位置放 API Keyhttp://AK-NAO6u57zbOWCmLaiVQuVW2tyt3rHpZrXkaQplocalhost:8081/user/getInfo源码中对以:结尾的值做了去尾处理因此AK-Xxx:形式的 Basic 串也能正确解析。一个容易忽略的细节读取用的参数名/头名是命名空间默认apikey。若按第 10 节创建了自定义命名空间的SaApiKeyTemplate对应的提交参数名也要换成该命名空间否则currentApiKey()读取不到。9、数据库模式实现 SaApiKeyDataLoader框架默认将所有 API Key 信息保存在缓存SaTokenDao中称之为“缓存模式”重启缓存库后数据将丢失。如需改为“数据库模式”实现SaApiKeyDataLoader接口即可其接口定义见 SaApiKeyDataLoader包含两个 default 方法getIsRecordIndex()框架是否保存索引信息默认取SaApiKeyConfig.isRecordIndexgetApiKeyModelFromDatabase(namespace, apiKey)根据 apiKey 从数据库获取ApiKeyModel默认返回null。官方文档给出的参考实现以 MyBatis Mapper 为例/** * API Key 数据加载器实现类 从数据库查询 */ Component public class SaApiKeyDataLoaderImpl implements SaApiKeyDataLoader { Autowired SaApiKeyMapper apiKeyMapper; // 指定框架不再维护 API Key 索引信息而是由我们手动从数据库维护 Override public Boolean getIsRecordIndex() { return false; } // 根据 apiKey 从数据库获取 ApiKeyModel 信息 实现此方法无需为数据做缓存处理框架内部已包含缓存逻辑 Override public ApiKeyModel getApiKeyModelFromDatabase(String namespace, String apiKey) { return apiKeyMapper.getApiKeyModel(apiKey); } }实现后框架内部逻辑的变化源码 getApiKey() 印证了“缓存未命中则查库并回写缓存”的流程需要注意以下事项调用SaApiKeyUtil.getApiKey(ApiKey)时会先从缓存查询查不到时调用getApiKeyModelFromDatabase从数据库加载并回写缓存框架不再维护 API Key 索引数据这意味着无法再调用SaApiKeyUtil.getApiKeyList(10001)获取某用户的全部 API Key需自行查库调用SaApiKeyUtil.saveApiKey(akModel)保存时只会把数据写入缓存请自行补充代码向数据库落库调用SaApiKeyUtil.deleteApiKey(ApiKey)时只删缓存中的数据不会删数据库记录请自行补充代码保证数据双删其它如getApiKey、checkApiKeyScope等查询与校验方法依旧可以正常调用。10、多账号模式命名空间隔离如果系统有多套账号体系比如 Admin 和 User只需为不同账号体系使用不同的命名空间即可。SaApiKeyTemplate的构造函数接受namespace参数见 源码命名空间同时决定了缓存 keytokenName:namespace:apiKey、Raw Session 索引和请求读取的参数名因此不同命名空间的数据天然隔离。User 账号的 API Key 继续使用原生SaApiKeyUtil默认命名空间apikey创建与校验Admin 账号则新建一个SaApiKeyTemplate实例// 新建 Admin 账号的 apiKeyTemplate 对象命名空间为 admin-apikey public static SaApiKeyTemplate adminApiKeyTemplate new SaApiKeyTemplate(admin-apikey); // 创建一个新的 ApiKey并返回 RequestMapping(/createApiKey) public SaResult createApiKey() { ApiKeyModel akModel adminApiKeyTemplate.createApiKeyModel(StpUtil.getLoginId()).setTitle(test); adminApiKeyTemplate.saveApiKey(akModel); return SaResult.data(akModel); } // ...校验、查询等操作均使用新创建的 adminApiKeyTemplate而非原生 SaApiKeyUtil这样 Admin 与 User 两套 API Key 各自独立互不冲突、互不越权且前端提交参数名也随之区分为admin-apikey与apikey。11、小结与延伸阅读Sa-Token 的 API Key 模块用极小的代码量提供了一套完整的“可控式部分授权”方案随机串生成带冲突检测、三级有效性校验存在/过期/禁用配细分错误码、AND/OR 双模式 Scope 校验、注解与编程式两种校验入口、缓存/数据库双模式存储以及基于命名空间的多账号隔离。对于需要向第三方系统、插件、脚本化任务开放接口能力的业务它可以替代“交出账号密码”或“直接给会话 token”的高风险做法。延伸阅读均在当前仓库内插件完整源码sa-token-apikey含 单元测试覆盖创建、查询、校验、索引、注解处理器等场景完整可运行示例sa-token-demo-apikey其它凭证与鉴权插件sa-token-signAPI 参数签名、sa-token-oauth2OAuth2.0 统一认证相关文档API Key 插件文档、参数签名插件文档。【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架让鉴权变得简单、优雅—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-Token创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Unity接入MediaPipe姿态数据的轻量级实时方案 2026/9/13 15:51:28

Unity接入MediaPipe姿态数据的轻量级实时方案

简介:本资源是一套基于Python与MediaPipe在Unity引擎中实现人体姿态追踪的完整实践方案,面向Unity初学者、计算机视觉入门者及跨领域项目开发者,解决多平台姿态数据实时采集与Unity可视化集成的技术难点。资源包共7个文件,包含2个…

阅读更多 →
lo 迭代器工具详解:使用 it.SeqToSeq2 为 Go 序列生成带索引的键值对 2026/9/13 15:51:28

lo 迭代器工具详解:使用 it.SeqToSeq2 为 Go 序列生成带索引的键值对

lo 迭代器工具详解:使用 it.SeqToSeq2 为 Go 序列生成带索引的键值对 【免费下载链接】lo 💥 A Lodash-style Go library based on Go 1.18 Generics (map, filter, contains, find...) 项目地址: https://gitcode.com/GitHub_Trending/lo/lo Seq…

阅读更多 →
How to Deploy to Production 2026/9/13 15:51:28

How to Deploy to Production

How to Deploy to Production 【免费下载链接】skills Skills Catalog for Codex 项目地址: https://gitcode.com/GitHub_Trending/skills4/skills Overview Production deployment using GitHub Actions with zero-downtime rolling updates. Time Required: 15-20 mi…

阅读更多 →
KernelSU 模块 WebUI 开发指南:从 webroot 目录到 JavaScript API 的完整实践 2026/9/13 15:51:28

KernelSU 模块 WebUI 开发指南:从 webroot 目录到 JavaScript API 的完整实践

KernelSU 模块 WebUI 开发指南:从 webroot 目录到 JavaScript API 的完整实践 【免费下载链接】KernelSU A Kernel based root solution for Android 项目地址: https://gitcode.com/GitHub_Trending/ke/KernelSU 导读 KernelSU 的模块不仅能执行开机脚本、…

阅读更多 →
基于Function Call的智能图书查询Agent设计与实现 2026/9/13 15:51:28

基于Function Call的智能图书查询Agent设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
15分钟上手|免费开源 RAW 调色工具 darktable 完整教程 2026/9/13 15:48:28

15分钟上手|免费开源 RAW 调色工具 darktable 完整教程

15分钟上手|免费开源 RAW 调色工具 darktable 完整教程 【免费下载链接】darktable darktable is an open source photography workflow application and raw developer 项目地址: https://gitcode.com/GitHub_Trending/da/darktable RAW 照片想精细调色&…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞