Sa-Token常用方法以及整合

Sa-Token

Sa-Token,是一个轻量级Java 权限认证框架,主要解决:登录认证、权限认证、单点登录、0Auth2.0、分布式session会话、微服务网关鉴权 等一系列权眼相关问题。

Sa-Token 旨在以简单、优雅的方式完成系统的权限认证部分,以登录认证为例,你只需要:

// 会话登录,参数填登录人的账号id 
StpUtil.login(10001);

无需实现任何接口,无需创建任何配置文件,只需要这一句静态代码的调用,便可以完成会话登录认证。

如果一个接口需要登录后才能访问,我们只需调用以下代码:

// 校验当前客户端是否已经登录,如果未登录则抛出 `NotLoginException` 异常
StpUtil.checkLogin();

具体方法参考官方文档,写的很详细 Sa-Token

整合Sa-Token

1.引入依赖

注:如果你使用的是 SpringBoot 3.x,只需要将 sa-token-spring-boot-starter 修改为 sa-token-spring-boot3-starter 即可。

<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.39.0</version>
</dependency>

2.设置yaml配置文件

server:
    # 端口
    port: 8081
    
############## Sa-Token 配置 (文档: https://sa-token.cc) ##############
sa-token: 
    # token 名称(同时也是 cookie 名称)
    token-name: satoken
    # token 有效期(单位:秒) 默认30天,-1 代表永久有效
    timeout: 2592000
    # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
    active-timeout: -1
    # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
    is-concurrent: false
    # 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
    is-share: true
    # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
    token-style: uuid
    # 是否输出操作日志 
    is-log: true

注意 要实现只能有一种设备登录某个账号的话 is-concurrent: false 要设置为false 默认为true
在controller测试即可

@RestController
@RequestMapping("/user/")
public class UserController {

    // 测试登录,浏览器访问: http://localhost:8081/user/doLogin?username=zhang&password=123456
    @RequestMapping("doLogin")
    public String doLogin(String username, String password) {
        // 此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对 
        if("zhang".equals(username) && "123456".equals(password)) {
            StpUtil.login(10001);
            return "登录成功";
        }
        return "登录失败";
    }

    // 查询登录状态,浏览器访问: http://localhost:8081/user/isLogin
    @RequestMapping("isLogin")
    public String isLogin() {
        return "当前会话是否登录:" + StpUtil.isLogin();
    }
    
}

还有许多常用的方法等等

登录校验

1.新建配置类,添加拦截器 这个是拦截所有请求

@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
    // 注册 Sa-Token 拦截器,打开注解式鉴权功能 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册 Sa-Token 拦截器,打开注解式鉴权功能 
        registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");    
    }
}

然后就可以使用注解鉴权了,比如下列注解

登录校验:只有登录之后才能进入该方法

@SaCheckLogin                        
@RequestMapping("info")
public String info() {
    return "查询用户信息";
}

// 角色校验:必须具有指定角色才能进入该方法 
@SaCheckRole("super-admin")        
@RequestMapping("add")
public String add() {
    return "用户增加";
}

1.1Sa-Token 还文持另外一种鉴权模式,通过编写 路由拦载代码实现鉴权,可以实现更灵活、集中式的鉴权能力。比如这个场景: 项目中所有接口均需要登录认证,只有“登录接口“本身对外开放。

@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
    // 注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册 Sa-Token 拦截器,校验规则为 StpUtil.checkLogin() 登录校验。
        registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
                .addPathPatterns("/**")
                .excludePathPatterns("/user/doLogin"); 
    }
}

2.定义权限与角色获取逻辑

部分接口需要特定的用户权限或对应的角色才能访问,那怎么知道当前登录用户具有哪些权限或角色呢?按照 Sa-Token 的开发模式,我们需要新建一个类,实现 stpInterface 接口。该接口提供了获取当前登录用户的权限和角色的方法,在每次调用鉴权代码时,都会执行接口中的方法。

@Component // 保证此类被 SpringBoot 扫描,完成 Sa-Token 的自定义权限验证扩展 
public class StpInterfaceImpl implements StpInterface {

    /**
     * 返回一个账号所拥有的权限码集合 (本项目没使用到)
     */
    @Override
    public List<String> getPermissionList(Object loginId, String s) {
        return new ArrayList<>();
    }

    /**
     * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)
     */
    @Override
    public List<String> getRoleList(Object loginId, String s) {
        // 从当前登录用户信息中获取角色
        User user = (User) StpUtil.getSessionByLoginId(loginId).get(USER_LOGIN_STATE);
        return Collections.singletonList(user.getUserRole());
    }
}

3.登录成功时,把用户信息添加到sa-Token中并设置设备类型

互斥原理

Sa-Token

        // 3. 记录用户的登录态
        // Sa-Token 登录,并
        StpUtil.login(user.getId(),DeviceUtils.getRequestDevice(request));
        //将用户信息存储到Session中,键是USER_LOGIN_STATE常量,值是user对象

        StpUtil.getSession().set(USER_LOGIN_STATE, user);

DeviceUtils.getRequestDevice(request) 获取设备类型工具类可在网上找,这里不做提供

user.getId()就是登录成功的用户id,可以在 stpInterfaceImpl 中通过方法参数 loginld 获取到。

注意,stputil.getSession()是 Sasession ,与 HttpSession 没任何关系,SaSession 是 Sa-Token 提供的会话中专业的数据缓存组件,通过 SaSession 我们可以很方便的缓存一些高频读写数据(比如登录用户信息),提高程序性能。

4.用户注销,移除登录状态

@Override
public boolean userLogout(HttpServletRequest request) {
    StpUtil.checkLogin();
    // 移除登录态
    StpUtil.logout();
    return true;
}

想使用什么注解直接参考官方文档即可

@SaCheckRole(UserConstant.ADMIN_ROLE) 只能是角色中包含管理员的才能进行访问

Sa-Token

可以将sa-Token抛出的异常捕获,友好的返回

在全局异常处理器中编写即可 还可参考官方文档做进一步的细化

Sa-Token

@ExceptionHandler(NotRoleException.class)
public BaseResponse<?> notRoleExceptionHandler(RuntimeException e) {
log.error("NotRoleException", e);
return ResultUtils.error(ErrorCode.NO_AUTH_ERROR, "无权限");
}

@ExceptionHandler(NotLoginException.class)
public BaseResponse<?> notLoginExceptionHandler(RuntimeException e) {
log.error("NotLoginException", e);
return ResultUtils.error(ErrorCode.NOT_LOGIN_ERROR, "未登录");
}

集成redis

Sa-Token 默认将数据保存在内存中,此模式读写速度最快,且避免了序列化与反序列化带来的性能消耗,但是此模式也有一些缺点,比如:

重启后数据会丢失 无法在分布式环境中共享数据

此时,可以将会话数据存储在一些专业的缓存中间件上(比如 Redis),做到重启数据不丢失,而且保证分布式环境下多节点的会话一致性。

可以参考 官方文档 整合 Redis,非常简单。集成 Redis 后,也不需要额外手动保存数据,框架会自动保存。集成Redis只需要引入对应的 pom依赖 即可,框架所有上层 API 保持不变。

1.引入依赖 和下面的1.1引入一个即可

<!-- Sa-Token 整合 Redis (使用 jdk 默认序列化方式) -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-redis</artifactId>
    <version>1.39.0</version>
</dependency>

优点:兼容性好,缺点:Session 序列化后基本不可读,对开发者来讲等同于乱码。
1.1基于jackson

<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-redis-jackson</artifactId>
    <version>1.39.0</version>
</dependency>

优点:Session 序列化后可读性强,可灵活手动修改,缺点:兼容性稍差。

1. 无论使用哪种序列化方式,你都必须为项目提供一个 Redis 实例化方案,例如:

<!-- 提供Redis连接池 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>


2.配置redis连接池信息

spring: 
    # redis配置 
    redis:
        # Redis数据库索引(默认为0)
        database: 1
        # Redis服务器地址
        host: 127.0.0.1
        # Redis服务器连接端口
        port: 6379
        # Redis服务器连接密码(默认为空)
        # password: 
        # 连接超时时间
        timeout: 10s
        lettuce:
            pool:
                # 连接池最大连接数
                max-active: 200
                # 连接池最大阻塞等待时间(使用负值表示没有限制)
                max-wait: -1ms
                # 连接池中的最大空闲连接
                max-idle: 10
                # 连接池中的最小空闲连接
                min-idle: 0


3. 集成 Redis 后,框架自动保存用户信息
框架自动保存。集成 Redis 只需要引入对应的 pom依赖 即可,框架所有上层 API 保持不变。

4. 集成包版本问题
Sa-Token-Redis 集成包的版本尽量与 Sa-Token-Starter 集成包的版本一致,否则可能出现兼容性问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值