当前位置: 首页 > 工具软件 > Sa-Token > 使用案例 >

Sa-Token权限认证框架

有骏奇
2023-12-01

官网:Sa-Token

Sa-Token: 轻量级,使得鉴权更加简单,优雅

主要解决:登录认证权限认证单点登录OAuth2.0分布式Session会话微服务网关鉴权

springboot项目使用方法:

1.添加依赖

<!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.31.0</version>
</dependency>
  1. 设置配置文件(可做可不做)

    server:
        # 端口
        port: 8081
    ​
    # Sa-Token配置
    sa-token: 
        # token 名称 (同时也是cookie名称)
        token-name: satoken
        # token 有效期,单位s 默认30天, -1代表永不过期 
        timeout: 2592000
        # token 临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
        activity-timeout: -1
        # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) 
        is-concurrent: true
        # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) 
        is-share: false
        # token风格
        token-style: uuid
        # 是否输出操作日志 
        is-log: false

3.创建启动类

@SpringBootApplication
public class SaTokenDemoApplication {
    public static void main(String[] args) throws JsonProcessingException {
        SpringApplication.run(SaTokenDemoApplication.class, args);
        System.out.println("启动成功:Sa-Token配置如下:" + SaManager.getConfig());
    }
}

sa-token的基本使用

登录认证

登录

// 会话登录:参数填写要登录的账号id,建议的数据类型:long | int | String, 不可以传入复杂类型,如:User、Admin 等等
StpUtil.login(Object id);     

关键: Sa-Token 为这个账号创建了一个Token凭证,且通过 Cookie 上下文返回给了前端

一般的会话登录接口

// 会话登录接口 
@RequestMapping("doLogin")
public SaResult doLogin(String name, String pwd) {
    // 第一步:比对前端提交的账号名称、密码
    if("zhang".equals(name) && "123456".equals(pwd)) {
        // 第二步:根据账号id,进行登录 
        StpUtil.login(10001);
        return SaResult.ok("登录成功");
    }
    return SaResult.error("登录失败");
}
​

cookie功能的基本两点

// 当前会话注销登录
StpUtil.logout();
​
// 获取当前会话是否已经登录,返回true=已登录,false=未登录
StpUtil.isLogin();
​
// 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`
StpUtil.checkLogin();
​

包含的异常: 异常 NotLoginException 代表当前会话暂未登录,可能的原因有很多: 前端没有提交 Token、前端提交的 Token 是无效的、前端提交的 Token 已经过期 …… 等等,

会话查询

// 获取当前会话账号id, 如果未登录,则抛出异常:`NotLoginException`
StpUtil.getLoginId();
​
// 类似查询API还有:
StpUtil.getLoginIdAsString();    // 获取当前会话账号id, 并转化为`String`类型
StpUtil.getLoginIdAsInt();       // 获取当前会话账号id, 并转化为`int`类型
StpUtil.getLoginIdAsLong();      // 获取当前会话账号id, 并转化为`long`类型
​
// ---------- 指定未登录情形下返回的默认值 ----------
​
// 获取当前会话账号id, 如果未登录,则返回null 
StpUtil.getLoginIdDefaultNull();
​
// 获取当前会话账号id, 如果未登录,则返回默认值 (`defaultValue`可以为任意类型)
StpUtil.getLoginId(T defaultValue);
​

Token查询

// 获取当前会话的token值
StpUtil.getTokenValue();
​
// 获取当前`StpLogic`的token名称
StpUtil.getTokenName();
​
// 获取指定token对应的账号id,如果未登录,则返回 null
StpUtil.getLoginIdByToken(String tokenValue);
​
// 获取当前会话剩余有效期(单位:s,返回-1代表永久有效)
StpUtil.getTokenTimeout();
​
// 获取当前会话的token信息参数
StpUtil.getTokenInfo();

测试

/**
 * 登录测试 
 */
@RestController
@RequestMapping("/acc/")
public class LoginController {
​
    // 测试登录  ---- http://localhost:8081/acc/doLogin?name=zhang&pwd=123456
    @RequestMapping("doLogin")
    public SaResult doLogin(String name, String pwd) {
        // 此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对 
        if("zhang".equals(name) && "123456".equals(pwd)) {
            StpUtil.login(10001);
            return SaResult.ok("登录成功");
        }
        return SaResult.error("登录失败");
    }
​
    // 查询登录状态  ---- http://localhost:8081/acc/isLogin
    @RequestMapping("isLogin")
    public SaResult isLogin() {
        return SaResult.ok("是否登录:" + StpUtil.isLogin());
    }
​
    // 查询 Token 信息  ---- http://localhost:8081/acc/tokenInfo
    @RequestMapping("tokenInfo")
    public SaResult tokenInfo() {
        return SaResult.data(StpUtil.getTokenInfo());
    }
​
    // 测试注销  ---- http://localhost:8081/acc/logout
    @RequestMapping("logout")
    public SaResult logout() {
        StpUtil.logout();
        return SaResult.ok();
    }
​
}

会自动生成一个token存在浏览器的cookies里面

权限认证

使用: 新建一个类,实现StpInterface接口

/**
 * 自定义权限验证接口扩展
 */
@Component   // 保证此类被SpringBoot扫描, 完成自定义权限扩展
public class StpInterfaceImpl implements StpInterface {
    @Override
    public List<String> getPermissionList(Object o, String s) {
        ArrayList<String> list = new ArrayList<>();
        list.add("101");
        list.add("user:add");
        list.add("user:delete");
        list.add("user:update");
​
        return list;
    }
​
    /**
     * 返回一个账号所拥有的角色标识的集合(权限与角色可以分开校验)
     * @param o
     * @param s
     * @return
     */
    @Override
    public List<String> getRoleList(Object o, String s) {
        ArrayList<String> list = new ArrayList<>();
        list.add("admin");
        list.add("super-admin");
        return list;
    }
}
​
拦截全局异常

@RestControllerAdvice
public class GlobalExceptionHandler {
    // 全局异常拦截 
    @ExceptionHandler
    public SaResult handlerException(Exception e) {
        e.printStackTrace(); 
        return SaResult.error(e.getMessage());
    }
}

上帝权限: 当一个账号拥有 "*" 权限时,他可以验证通过任何权限码 (角色认证同理)

踢人下线

1.强制注销

StpUtil.logout(10001);                    // 强制指定账号注销下线 
StpUtil.logout(10001, "PC");              // 强制指定账号指定端注销下线 
StpUtil.logoutByTokenValue("token");      // 强制指定 Token 注销下线 

注解鉴权

2.踢人下线

 
 // 将指定账号踢下线 
StpUtil.kickout(10001);
// 将指定账号指定端踢下线
StpUtil.kickout(10001, "PC"); 
 // 将指定 Token 踢下线
StpUtil.kickoutByTokenValue("token");
  ```

两者的区别

强制注销 和 踢人下线 的区别在于:

  • 强制注销等价于对方主动调用了注销方法,再次访问会提示:Token无效。

  • 踢人下线不会清除Token信息,而是将其打上特定标记,再次访问会提示:Token已被踢下线。

注解鉴权

注解鉴权 —— 优雅的将鉴权与业务代码分离!

  • @SaCheckLogin: 登录认证 —— 只有登录之后才能进入该方法。

  • @SaCheckRole("admin"): 角色认证 —— 必须具有指定角色标识才能进入该方法。

  • @SaCheckPermission("user:add"): 权限认证 —— 必须具有指定权限才能进入该方法。

  • @SaCheckSafe: 二级认证校验 —— 必须二级认证之后才能进入该方法。

  • @SaCheckBasic: HttpBasic认证 —— 只有通过 Basic 认证后才能进入该方法。

  • @SaIgnore:忽略认证 —— 表示被修饰的方法或类无需进行注解认证和路由拦截认证。

  • @SaCheckDisable("comment"):账号服务封禁校验 —— 校验当前账号指定服务是否被封禁

a-Token 使用全局拦截器完成注解鉴权功能,为了不为项目带来不必要的性能负担,拦截器默认处于关闭状态因此,为了使用注解鉴权,你必须手动将 Sa-Token 的全局拦截器注册到你项目中

/**
 * @BelongsProject: saToken
 * @BelongsPackage: com.example.config
 * @Author: Mr.Hua
 * @CreateTime: 2022-10-09  17:22
 * @Description: TODO
 * @Version: 1.0
 */
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
    // 注册 sa token 拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
         // 注册 Sa-Token 拦截器 打开注解鉴权
        registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
    }
​
}

路由拦截鉴权

Session会话

框架配置

未完待续.....

 类似资料: