news 2026/9/13 12:17:46

Sa-Token SaStrategy 全局策略:核心逻辑代理封装与自定义扩展指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Sa-Token SaStrategy 全局策略:核心逻辑代理封装与自定义扩展指南

Sa-Token SaStrategy 全局策略:核心逻辑代理封装与自定义扩展指南

【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架,让鉴权变得简单、优雅!—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-Token

SaStrategy(全局策略)是 Sa-Token 框架中统一定义关键性逻辑算法的入口,以全局单例的形式将 Token 生成、Session 创建、唯一性校验、自动续期、配置读取等核心行为抽象为可替换的函数式策略。本文以 sa-token-doc-new/docs/api/sa-strategy.md 为骨架,结合 SaStrategy.java 源码与 SaStrategyTest.java 测试用例,完整讲解每一个内置策略的默认实现、重写方法与应用场景,读完即可按需定制 Sa-Token 的核心行为(如自定义 Token 算法、从数据库动态加载配置)。


一、SaStrategy 是什么:核心逻辑的"代理封装"

Sa-Token 框架内部分散着大量关键性算法:如何创建 Token、如何创建 Session、如何判断权限集合、如何生成不重复的 token、是否续期、如何匹配路由……在引入 SaStrategy 之前,这些逻辑散落在框架各处,开发者想要定制只能改动框架源码。

SaStrategy 的设计目标,正如 SaStrategy.java 的类注释所述:

此类统一定义框架内的一些关键性逻辑算法,方便开发者进行按需重写。

它的核心形态是一个持有大量函数式接口字段的全局单例

  • 全局单例:通过public static final SaStrategy instance = new SaStrategy();暴露,构造器私有,全框架共享同一实例(源码见 SaStrategy.java);
  • 函数式字段:每个策略都是一个 Java 函数式接口(BiFunctionFunctionSupplier等),默认提供框架内置实现,开发者可直接为字段赋值覆盖;
  • set 连缀风格:每个策略字段都配有一个返回thissetXxx方法,支持链式调用,同时保留对旧版SaStrategy.me的兼容(已标注@Deprecated,建议使用instance,见 SaStrategy.java)。

策略接口统一收拢在cn.dev33.satoken.fun.strategy包下(见 fun/strategy 目录),包括SaCreateTokenFunctionSaCreateSessionFunctionSaHasElementFunctionSaGenerateUniqueTokenFunctionSaAutoRenewFunctionSaCreateStpLogicFunctionSaRouteMatchFunctionSaCorsHandleFunctionSaGetSaTokenConfigFunction以及 SaRequest/SaResponse/SaStorage 创建策略等。

从使用方式看,框架内部各模块通过SaStrategy.instance.xxx调用这些策略(例如 StpLogic.java 中createToken、StpLogic.java 中hasElement),因此只要替换对应字段,框架所有调用方会一并生效——这正是"代理封装"的含义:策略层是框架逻辑的唯一入口,替换策略即替换行为


二、核心策略详解:默认实现与可替换行为

以下 10 项策略完整覆盖 sa-strategy.md 文档中的核心策略清单,并逐一补充源码级默认实现说明。

2.1 createToken:创建 Token 的策略

  • 函数签名BiFunction<Object, String, String>,参数为[账号id, 账号类型],返回 Token 字符串;
  • 重写入口setCreateToken(...)

文档中默认实现简写为"xxxxx-xxxxx-xxxxx-xxxxx"(UUID 形态)。对照源码,实际默认实现远比这丰富:它会读取该账号体系配置中的tokenStyle,按风格生成不同格式的 Token(见 SaStrategy.java):

tokenStyle 配置值生成结果测试断言(见 SaStrategyTest)
uuid(默认)UUID.randomUUID().toString(),形如xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,含-断言包含-
simple-uuidUUID 去掉所有-,固定 32 位断言长度为 32 且不含-
random-3232 位随机字符串断言长度为 32
random-6464 位随机字符串断言长度为 64
random-128128 位随机字符串断言长度为 128
tik2位随机 + "_" + 14位随机 + "_" + 16位随机 + "__"断言以__结尾
其他非法值打印 warn 日志并回退为 UUID断言回退结果含-

以上行为在 SaStrategyTest.java 的createToken_byTokenStyle测试中逐一验证。

自定义示例(如接入 JWT 或自研 token 格式):

SaStrategy.instance.setCreateToken((loginId, loginType) -> { // 这里可以基于 loginId、loginType 自定义生成算法,例如拼接业务前缀 return "MY-" + loginId + "-" + System.currentTimeMillis(); });

2.2 createSession:创建 Session 的策略

  • 函数签名Function<String, SaSession>,参数为[SessionId],返回SaSession实例;
  • 重写入口setCreateSession(...)

默认实现sessionId -> new SaSession(sessionId)(见 SaStrategy.java),即创建框架标准的SaSession。测试createSession_hasElement_generateUniqueToken中验证默认创建的 Session 能正确保留传入的 id(见 SaStrategyTest.java)。

典型应用:当项目需要自定义 Session 实现(例如继承SaSession扩展字段),可在此策略中返回自定义子类:

SaStrategy.instance.setCreateSession((sessionId) -> { return new MySaSession(sessionId); // MySaSession 继承自 SaSession });

2.3 sessionClassType:反序列化 SaSession 的默认类型

  • 类型volatile Class<? extends SaSession>
  • 默认值SaSession.class(见 SaStrategy.java)。

该字段用于指定从持久化层反序列化SaSession时使用的类型。若 2.2 中自定义了 Session 子类,通常需要同步将此字段改为对应子类的Class,保证反序列化后仍是自定义类型。注意这是一个直接字段赋值volatile保证多线程可见性),文档未提供对应 set 方法,赋值方式为SaStrategy.instance.sessionClassType = MySaSession.class;

2.4 hasElement:集合模糊匹配策略

  • 函数签名BiFunction<List<String>, String, Boolean>,参数为[集合, 元素],返回是否命中;
  • 重写入口setHasElement(...)

文档中的默认实现简写为return false,仅示意"可替换"。实际默认实现是一个先精确匹配、后通配符模糊匹配的两段式算法(见 SaStrategy.java):

  1. 集合为空(nullsize() == 0)直接返回false
  2. 先尝试list.contains(element)精确匹配,命中即返回true
  3. 遍历集合,用SaFoxUtil.vagueMatch(patt, element)逐个做通配符匹配。

典型场景:权限/角色校验。例如角色列表为["admin", "user:*"]时,元素user:1001可通过user:*通配命中。测试 SaStrategyTest.java 验证了null、空集合返回 false、精确匹配与通配匹配均正确。

该策略被StpUtil.hasElement(...)间接调用(StpLogic.hasElement委托给SaStrategy.instance.hasElement,见 StpLogic.java),进而影响hasRolehasPermission等权限判断逻辑。

2.5 generateUniqueToken:生成唯一式 Token 的算法

  • 函数签名SaGenerateUniqueTokenFunction,参数为[元素名称, 最大尝试次数, 创建 token 函数, 检查 token 函数],返回唯一 Token(函数式接口定义见 SaGenerateUniqueTokenFunction.java);
  • 重写入口setGenerateUniqueToken(...)

文档中的默认实现简写为return "xxxxxx"。真实默认实现是一个"循环生成 + 唯一性校验 + 失败重试"算法(见 SaStrategy.java):

  1. 调用createTokenFunction.get()生成一个 token;
  2. maxTryTimes == -1,表示不做唯一性验证,直接返回;
  3. 否则调用checkTokenFunction.apply(token),返回true说明可用,立即返回;
  4. 循环超过maxTryTimes次仍未成功,抛出SaTokenException,提示"生成算法过于简单或资源池已耗尽"。

该接口的四个参数语义(见 SaGenerateUniqueTokenFunction.java)为:elementName用于组织异常提示信息;maxTryTimes最大尝试次数;createTokenFunction负责生成;checkTokenFunction负责校验唯一性(返回 true 表示可用)。

框架内真实调用链StpUtil.login()创建新 token 时会执行该策略(见 StpLogic.java),传入的checkTokenFunctiongetLoginIdNotHandle(tokenValue) == null,即"该 token 在数据源中查不到任何账号"才认为可用;该策略同样被用于 SSO 的 ticket、临时 token(SaTempTemplate)等"需要保证唯一性"的元素的生成。

测试验证(见 SaStrategyTest.java):

  • 生成器依次产出tk-1/tk-2/tk-3,校验器要求以3结尾,最终返回tk-3
  • 固定生成"same"且校验器永远返回 false、maxTryTimes=2时,抛出SaTokenException
  • maxTryTimes=-1时跳过校验直接返回。

2.6 autoRenew:是否自动续期 active-timeout 的策略

  • 函数签名Function<StpLogic, Boolean>,参数为当前StpLogic实例,返回true自动续期、false不自动续期;
  • 重写入口setAutoRenew(...)

默认实现stpLogic -> stpLogic.getConfigOrGlobal().getAutoRenew()(见 SaStrategy.java),即直接读取配置项autoRenew(默认开启)。文档特别强调:"每次续期前都会执行,可以加入动态判断逻辑"——这意味着该策略的执行频率很高,可用于在续期前加入自定义业务判断。

典型应用:例如要求"仅在工作时间自动续期"或"VIP 账号自动续期、普通账号不续期":

SaStrategy.instance.setAutoRenew((stpLogic) -> { // 例:读配置为 true,但可附加业务动态判断 return stpLogic.getConfigOrGlobal().getAutoRenew(); });

该策略在 StpLogic.java 附近被调用,作为会话活跃度续期的开关。测试autoRenew_createStpLogic_andNotImplStrategies验证了配置autoRenew=false时策略返回false(见 SaStrategyTest.java)。

2.7 createStpLogic:创建 StpLogic 的算法

  • 函数签名SaCreateStpLogicFunction,参数为[账号体系标识 loginType],返回创建好的StpLogic对象;
  • 重写入口setCreateStpLogic(...)

默认实现loginType -> new StpLogic(loginType)(见 SaStrategy.java)。StpLogic是每个账号体系(如loginuseradmin)的逻辑封装,Sa-Token 支持多账号体系并行鉴权,此策略决定了每个loginType对应的StpLogic如何创建。

典型应用:当项目继承StpLogic并扩展方法时,通过重写此策略让所有账号体系都使用自定义子类:

SaStrategy.instance.setCreateStpLogic((loginType) -> { return new MyStpLogic(loginType); // MyStpLogic 继承 StpLogic });

测试中验证了默认实现创建的StpLogic能正确携带loginType,且链式 set 后可生成"chain-app"这种带前缀的 loginType(见 SaStrategyTest.java)。

2.8 routeMatcher:路由匹配策略

  • 函数签名SaRouteMatchFunction,参数为[pattern, path],返回是否匹配;
  • 重写入口SaStrategy.instance.routeMatcher = ...(文档未单独提供 set 方法,需直接字段赋值)。

这是少数默认未实现的策略之一:默认实现直接抛出NotImplException,错误码CODE_12401("未实现具体路由匹配策略",见 SaStrategy.java)。它由SaRouter路由拦截模块消费(SaRouter.java),具体实现由各集成插件(Servlet、WebFlux、Solon 等)注入。

测试中确认默认状态抛出NotImplException(见 SaStrategyTest.java)。普通业务开发者一般不需要修改此策略,除非要定制路由通配符语法。

2.9 corsHandle:CORS 策略处理函数

  • 函数签名SaCorsHandleFunction,参数为[请求包装对象, 响应包装对象, 数据读写对象]
  • 重写入口SaStrategy.instance.corsHandle = ...(直接字段赋值)。

默认实现为空操作(req, res, sto) -> {}(见 SaStrategy.java),即默认不处理 CORS,测试验证空实现可正常执行、不抛异常(见 SaStrategyTest.java)。当项目需要基于请求/响应包装对象动态写入 CORS 响应头时,可在此策略内完成。更常见的 CORS 解决方案可参考仓库文档中的全局过滤器配置(见 sa-token-doc/up/global-filter.md)。

2.10 getSaTokenConfig:获取 SaTokenConfig 的策略

  • 函数签名SaGetSaTokenConfigFunction,其本质是Supplier<SaTokenConfig>(见 SaGetSaTokenConfigFunction.java);
  • 默认值null,表示不启用,使用框架内置逻辑;
  • 重写入口setGetSaTokenConfig(...)

这是文档重点介绍、也最具实战价值的策略,详见下一节专章。

补充:未列出的其他策略:源码中还定义了createSaRequest/createSaResponse/createSaStorage三个上下文对象创建策略(分别对应CODE_12402/CODE_12403/CODE_12404,默认抛NotImplException,由各集成层实现,见 SaStrategy.java)。它们不属于业务定制范围,通常无需修改。


三、getSaTokenConfig:从外部数据源动态读取配置

3.1 默认配置加载链路

getSaTokenConfignull时,SaManager.getConfig()走框架内置逻辑(见 SaManager.java):

  1. 若全局config字段已初始化,直接返回;
  2. 若为空,在类锁内通过SaTokenConfigFactory.createConfig()创建配置(默认读取sa-token.properties等配置文件);
  3. 返回并缓存到config字段。

3.2 启用自定义策略后的行为变化

一旦执行setGetSaTokenConfig(...)赋值(非 null),SaManager.getConfig()每次调用都会直接执行此策略并返回其结果,完全绕过内置加载链路(见 SaManager.java 的优先分支)。测试setCreateContextAndConfigChainMethods验证了策略返回的SaTokenConfig会被原样读取(见 SaStrategyTest.java)。

3.3 官方使用示例(文档原版,可直接复制运行)

SaStrategy.instance.setGetSaTokenConfig(() -> { // 从数据库读取配置,自行做好缓存 SaTokenConfig config = new SaTokenConfig(); config.setTokenName("satoken"); config.setTimeout(30 * 24 * 60 * 60); return config; });

3.4 两条强制注意点

根据文档与源码双重确认,使用该策略必须遵守:

  1. 严禁递归调用:策略内部不要调用SaManager.getConfig(),否则每次调用都会再次进入本策略,形成无限递归(源码注释与 SaGetSaTokenConfigFunction.java 均明确警告);
  2. 必须自行缓存:启用后SaManager.getConfig()每次调用都会执行策略,若每次都在策略内查询数据库,将带来明显性能开销。建议在策略内加一层缓存(内存缓存、Caffeine 等),并在配置变更时主动刷新。

典型应用场景:需要将 token 有效期、token 名称等配置动态化管理(存于数据库、配置中心),改动后无需重启应用即可生效。这是"动态配置"需求的标准落地方式,官方描述为"适用于需要从数据库等外部数据源动态读取配置的场景"。


四、重写策略:set 连缀风格与实操要点

4.1 所有重写入口一览

文档给出 7 个 set 方法,全部采用"返回this"的连缀风格(源码见 SaStrategy.java),可一行链式重写多个策略:

SaStrategy.instance .setCreateToken(createToken) // 重写创建 Token 的策略 .setCreateSession(createSession) // 重写创建 Session 的策略 .setHasElement(hasElement) // 重写集合模糊匹配策略 .setGenerateUniqueToken(generateUniqueToken)// 重写生成唯一 token 的策略 .setCreateStpLogic(createStpLogic) // 重写创建 StpLogic 的策略 .setAutoRenew(autoRenew) // 重写是否自动续期策略 .setGetSaTokenConfig(getSaTokenConfig); // 重写获取 SaTokenConfig 的策略

除文档列出的 7 个方法外,源码还提供setCreateSaRequestsetCreateSaResponsesetCreateSaStorage三个上下文创建策略的重写方法(见 SaStrategy.java),主要用于集成层定制。

4.2 链式调用的测试验证

测试 SaStrategyTest.java 验证了链式 set 的行为:

  • 每个 set 方法返回的都是SaStrategy自身(assertSame(strategy, strategy.setGenerateUniqueToken(...)));
  • 替换后,createToken返回自定义值"custom-token"createSession生成"custom-sid"前缀 Session、hasElement恒为trueautoRenew侧生效(AtomicBoolean被置为 true)、createStpLogic生成"chain-app"

4.3 实操要点

  • 重写位置:建议在应用启动阶段(如 Spring Boot 的@Configuration类、CommandLineRunner或静态初始化块)统一完成重写,避免运行时动态更换导致行为不一致;
  • 全局生效instance是全局单例,任何位置的重写都会影响整个框架所有账号体系,重写前请确认不会影响其他模块(如 SSO、OAuth2 插件同样消费这些策略);
  • 字段 vs 方法createToken等策略既有公开字段也有 set 方法;sessionClassTyperouteMatchercorsHandle没有对应 set 方法,需直接字段赋值。新代码统一推荐使用setXxx方法 +instanceme已废弃)。

五、完整落地示例:一个"自定义 Token + 动态配置"的综合配置类

综合以上策略,给出一个完整的可运行示例(以 Spring Boot 风格为例),一次性演示createTokenhasElementgetSaTokenConfig三个策略的组合使用:

import cn.dev33.satoken.config.SaTokenConfig; import cn.dev33.satoken.strategy.SaStrategy; import org.springframework.context.annotation.Configuration; @Configuration public class SaTokenStrategyConfig { public SaTokenStrategyConfig() { // 1、自定义 Token 生成算法:业务前缀 + 时间戳 SaStrategy.instance.setCreateToken((loginId, loginType) -> "MY-" + loginType + "-" + loginId + "-" + System.currentTimeMillis() ); // 2、定制权限模糊匹配:追加自定义通配规则 SaStrategy.instance.setHasElement((list, element) -> { if (list == null || list.size() == 0) { return false; } if (list.contains(element)) { return true; } // 追加一条自定义规则:element 以 list 中任一元素开头即视为匹配 for (String patt : list) { if (element.startsWith(patt)) { return true; } } return false; }); // 3、从数据库动态读取配置(内部需做好缓存,严禁回调 SaManager.getConfig()) SaStrategy.instance.setGetSaTokenConfig(() -> { SaTokenConfig config = new SaTokenConfig(); config.setTokenName("satoken"); config.setTimeout(30 * 24 * 60 * 60); // 30 天,单位:秒 // 实际项目中可改为从数据库/配置中心读取 return config; }); } }

六、小结:策略层定位与适用边界

  • 定位:SaStrategy 是 Sa-Token 核心逻辑的代理封装层,把分散的算法收敛为可替换的函数式策略字段,框架内部所有关键调用点(Token 创建、Session 创建、权限匹配、唯一性生成、活跃续期、配置读取等)都统一经过该单例;
  • 适用场景:自定义 Token 格式(createToken)、自定义 Session 类型(createSession+sessionClassType)、定制权限通配规则(hasElement)、控制自动续期行为(autoRenew)、多账号体系定制(createStpLogic)、外部数据源动态配置(getSaTokenConfig);
  • 不适用边界routeMatchercreateSaRequest/createSaResponse/createSaStorage属于集成层职责,默认抛NotImplException,由各集成插件实现,业务层无需(也不应)随意替换。

延伸阅读:关于SaTokenConfig各配置项(如tokenStyleautoRenewtimeout)的完整说明,可参见 sa-token-doc/use/config.md;Session 相关 API 见 sa-token-doc/api/sa-session.md;DAO 数据源扩展见 sa-token-doc/api/sa-token-dao.md。

【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架,让鉴权变得简单、优雅!—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-Token

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 12:16:51

Tasmota 如何用 QEMU 在本地模拟 ESP32 固件启动并打开 WebUI

Tasmota 如何用 QEMU 在本地模拟 ESP32 固件启动并打开 WebUI 【免费下载链接】Tasmota Alternative firmware for ESP8266 and ESP32 based devices with easy configuration using webUI, OTA updates, automation using timers or rules, expandability and entirely local …

作者头像 李华
网站建设 2026/9/13 12:15:59

阿里云数据中台治理:提升企业数据资产价值

1. 数据中台与大数据治理的核心价值在数字化转型浪潮中&#xff0c;企业数据量呈现指数级增长。我们团队在金融行业的数据治理项目中发现&#xff0c;某省级银行的数据资产中仅有35%被有效利用&#xff0c;其余数据要么因质量问题无法使用&#xff0c;要么因缺乏统一标准而成为…

作者头像 李华
网站建设 2026/9/13 12:15:22

pip conda python的包管理 虚拟环境env

增删改查包pip install <path> # 安装本地包whl 或 文件夹中有setup.py pip install torch1.13.0cu116 # 安装包 pip install --upgrade websockets # 更新包 pip install -r requirements.txt # 根据文件安装包pip show numpy …

作者头像 李华
网站建设 2026/9/13 12:15:07

企业级私有AI助手Dify部署与优化指南

1. 项目概述&#xff1a;企业级私有AI助手的价值定位在数字化转型浪潮中&#xff0c;知识管理已成为企业核心竞争力的关键要素。传统知识库系统存在检索效率低、交互体验差等痛点&#xff0c;而公有云AI服务又面临数据安全风险。Dify作为开源AI应用开发平台&#xff0c;恰好填补…

作者头像 李华
网站建设 2026/9/13 12:14:45

SPC统计过程控制:原理、实施与应用指南

1. SPC基础概念解析 统计过程控制&#xff08;Statistical Process Control&#xff0c;简称SPC&#xff09;是一套运用统计方法对生产过程进行监控与改进的质量管理技术。它的核心思想是通过收集和分析生产过程中的数据&#xff0c;识别异常波动&#xff0c;从而实现对质量的预…

作者头像 李华