Back to Sa Token

Sa-Token

sa-token-doc/blog/essays/sa-token-ji-cheng-jwt.html

1.46.08.2 KB
Original Source

Sa-Token 集成 jwt

2023-04-24随笔

Sa-Token 是一个轻量级 java 权限认证框架,主要解决登录认证、权限认证、单点登录、OAuth2、微服务网关鉴权 等一系列权限相关问题。

Gitee 开源地址:https://gitee.com/dromara/sa-token

很多小伙伴关心的一个话题,那就是 Sa-Token 和 JWT 哪个更好用一些,其实不用纠结这个问题,Sa-Token 提供了 sa-token-jwt 插件,
可以将 Sa-Token 和 jwt 结合起来,这样我们就可以既有 Sa-Token 进行方便的鉴权,又可以得到 jwt 的 Token 扩展参数能力了。

下面我将介绍如何在 Sa-Token 中方便的集成 jwt。

一、引入依赖

首先在项目 pom.xml 中引入:

xml
<!-- SpringBoot 集成 Sa-Token -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.34.0</version>
</dependency>

<!-- Sa-Token 整合 jwt -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-jwt</artifactId>
    <version>1.34.0</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

Gradle 方式:

gradle
// SpringBoot 集成 Sa-Token
implementation 'cn.dev33:sa-token-spring-boot-starter:1.34.0'

// Sa-Token 整合 jwt
implementation 'cn.dev33:sa-token-jwt:1.34.0'
  • 1
  • 2
  • 3
  • 4
  • 5

注意: sa-token-jwt 显式依赖 hutool-jwt 5.7.14 版本,意味着:你的项目中要么不引入 Hutool,要么引入版本 >= 5.7.14 的 Hutool 版本

二、配置秘钥

application.yml 配置文件中配置 jwt 生成秘钥:

yaml
sa-token:
    # jwt秘钥 
    jwt-secret-key: asdasdasifhueuiwyurfewbfjsdafjk
  • 1
  • 2
  • 3

注:为了安全起见请不要直接复制官网示例这个字符串(随便按几个字符就好了)

三、注入jwt实现

根据不同的整合规则,插件提供了三种不同的模式,你需要 选择其中一种 注入到你的项目中

Simple 简单模式:Token 风格替换

java
@Configuration
public class SaTokenConfigure {
    // Sa-Token 整合 jwt (Simple 简单模式)
    @Bean
    public StpLogic getStpLogicJwt() {
        return new StpLogicJwtForSimple();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Mixin 混入模式:混入部分逻辑

java
@Configuration
public class SaTokenConfigure {
    // Sa-Token 整合 jwt (Mixin 混入模式)
    @Bean
    public StpLogic getStpLogicJwt() {
        return new StpLogicJwtForMixin();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Stateless 无状态模式:服务器完全无状态

java
@Configuration
public class SaTokenConfigure {
    // Sa-Token 整合 jwt (Stateless 无状态模式)
    @Bean
    public StpLogic getStpLogicJwt() {
        return new StpLogicJwtForStateless();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

四、开始使用

然后我们就可以像之前一样使用 Sa-Token 了

java
/**
 * 登录测试 
 */
@RestController
@RequestMapping("/acc/")
public class LoginController {

    // 测试登录
    @RequestMapping("login")
    public SaResult login() {
        StpUtil.login(10001);
        return SaResult.ok("登录成功");
    }

    // 查询登录状态
    @RequestMapping("isLogin")
    public SaResult isLogin() {
        return SaResult.ok("是否登录:" + StpUtil.isLogin());
    }

    // 测试注销
    @RequestMapping("logout")
    public SaResult logout() {
        StpUtil.logout();
        return SaResult.ok();
    }

}
  • 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

访问上述接口,观察Token生成的样式

java
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbklkIjoiMTAwMDEiLCJybiI6IjZYYzgySzBHVWV3Uk5NTTl1dFdjbnpFZFZHTVNYd3JOIn0.F_7fbHsFsDZmckHlGDaBuwDotZwAjZ0HB14DRujQfOQ
  • 1

五、不同模式策略对比

注入不同模式会让框架具有不同的行为策略,以下是三种模式的差异点(为方便叙述,以下比较以同时引入 jwt 与 Redis 作为前提):

功能点Simple 简单模式Mixin 混入模式Stateless 无状态模式
Token风格jwt风格jwt风格jwt风格
登录数据存储Redis中存储Token中存储Token中存储
Session存储Redis中存储Redis中存储无Session
注销下线前后端双清数据前后端双清数据前端清除数据
踢人下线API支持不支持不支持
顶人下线API支持不支持不支持
登录认证支持支持支持
角色认证支持支持支持
权限认证支持支持支持
timeout 有效期支持支持支持
activity-timeout 有效期支持支持不支持
id反查Token支持支持不支持
会话管理支持部分支持不支持
注解鉴权支持支持支持
路由拦截鉴权支持支持支持
账号封禁支持支持不支持
身份切换支持支持支持
二级认证支持支持支持
模式总结Token风格替换jwt 与 Redis 逻辑混合完全舍弃Redis,只用jwt

六、扩展参数

你可以通过以下方式在登录时注入扩展参数:

java
// 登录10001账号,并为生成的 Token 追加扩展参数name
StpUtil.login(10001, SaLoginConfig.setExtra("name", "zhangsan"));

// 连缀写法追加多个
StpUtil.login(10001, SaLoginConfig
                .setExtra("name", "zhangsan")
                .setExtra("age", 18)
                .setExtra("role", "超级管理员"));

// 获取扩展参数 
String name = StpUtil.getExtra("name");

// 获取任意 Token 的扩展参数 
String name = StpUtil.getExtra("tokenValue", "name");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

七、在多账户模式中集成 jwt

sa-token-jwt 插件默认只为 StpUtil 注入 StpLogicJwtFoxXxx 实现,自定义的 StpUserUtil 是不会自动注入的,我们需要帮其手动注入:

java
/**
 * 为 StpUserUtil 注入 StpLogicJwt 实现 
 */
@Autowired
public void setUserStpLogic() {
    StpUserUtil.setStpLogic(new StpLogicJwtForSimple(StpUserUtil.TYPE));
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

八、自定义 SaJwtUtil 生成 token 的算法

如果需要自定义生成 token 的算法(例如更换sign方式),直接重写 SaJwtTemplate 对象即可:

java
/**
 * 自定义 SaJwtUtil 生成 token 的算法 
 */
@Autowired
public void setSaJwtTemplate() {
    SaJwtUtil.setSaJwtTemplate(new SaJwtTemplate() {
        @Override
        public String generateToken(JWT jwt, String keyt) {
            System.out.println("------ 自定义了 token 生成算法");
            return super.generateToken(jwt, keyt);
        }
    });
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

九、注意点

1、使用 jwt-simple 模式后,is-share=false 恒等于 false。

is-share=true 的意思是每次登录都产生一样的 token,这种策略和 [为每个 token 单独设定 setExtra 数据] 不兼容的,
为保证正确设定 Extra 数据,当使用 jwt-simple 模式后,is-share 配置项 恒等于 false

2、使用 jwt-mixin 模式后,is-concurrent 必须为 true。

is-concurrent=false 代表每次登录都把旧登录顶下线,但是 jwt-mixin 模式登录的 token 并不会记录在持久库数据中,
技术上来讲无法将其踢下线,所以此时顶人下线和踢人下线等 API 都属于不可用状态,所以此时 is-concurrent 配置项必须配置为 true


参考资料

← Sa-Token 多账号认证:同时为系统的 Admin 账号和 User 账号提供鉴权操作SpringBoot 使用 Sa-Token 完成权限认证 →