美文网首页
2022-04-19_spring boot 配置sa-toke

2022-04-19_spring boot 配置sa-toke

作者: 微笑碧落 | 来源:发表于2022-04-18 22:30 被阅读0次

spring boot 配置sa-token

前言

  • sa-token一个国产的,权限认证框架。
  • 功能上类似Apache ShiroSpring Security等。但是更加强大、容易上手
  • 主要解决: 登录认证、权限认证、Session会话 等一系列权限相关问题。大部分api调用都是一行代码就能解决
  • sa-token功能很强大。以下简单记录登录认证、权限认证、路由拦截鉴权等功能
  • sa-token中,登录授权就是如此的简单,不需要什么全局过滤器,不需要各种乱七八糟的配置!只需要一行简单的API调用,即可完成会话的登录授权!
  • 只要完成登录认证、权限认证、路由拦截鉴权就可以简单的为项目增加一个鉴权系统。
  • 如果只需要登录认证,权限认证都不需要,就更简单了。。写一个路由拦截配置文件、用户登录调用login方法就搞定一切了。

1.spring boot 引入sa-token

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

2.配置

  • application.yml文件增加如下配置项目,当然也可以不增加:

  • # 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.登录认证

  • 所谓登录认证,说白了就是限制某些API接口必须登录后才能访问。

  • 如何判断一个会话是否已经登录?用户登录后,服务器端调用login方法。sa-token会帮我们对会话进行做个标记。每次需要登录认证的时候校验这些标记。有标记者视为已登录,无标记者视为未登录。

  • 默认,不特殊处理的情况下,sa-token是通过cookie来标记的。如果清掉了cookie,则需要重新登录。

  • // 标记当前会话登录的账号id 
    // 建议的参数类型:long | int | String, 不可以传入复杂类型,如:User、Admin等等
    StpUtil.login(Object id);     
    
    // 当前会话注销登录
    StpUtil.logout();
    
    // 获取当前会话是否已经登录,返回true=已登录,false=未登录
    StpUtil.isLogin();
    
    // 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`
    StpUtil.checkLogin()
    
    // 获取当前会话账号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对应的账号id,如果未登录,则返回 null
    StpUtil.getLoginIdByToken(String tokenValue);
    
    // 获取当前`StpLogic`的token名称
    StpUtil.getTokenName();
    
    // 获取当前会话的token值
    StpUtil.getTokenValue();
    
    // 获取当前会话的token信息参数
    StpUtil.getTokenInfo();
    
    

4.权限认证

  • 所谓权限认证,认证的核心就是一个账号是否拥有一个权限码。有,就让你通过。没有?那么禁止访问!

  • 再往底了说,就是每个账号都会拥有一个权限码集合,我来校验这个集合中是否包含指定的权限码

  • 例如:当前账号拥有权限码集合:["user-add", "user-delete", "user-get"],这时候我来校验权限 "user-update",则其结果就是:验证失败,禁止访问

  • 所以核心问题如下:

4.1 获取当前账号的权限码集合

  • 你需要做的就是新建一个类,实现StpInterface接口

  • 添加@Component保证此类被SpringBoot扫描,完成Sa-Token的自定义权限验证扩展

  • 注意方法传入的loginID。实际项目需要更加loginID实际返回该ID对于的权限。

  • /**
     * 自定义权限验证接口扩展 
     */
    @Component    // 保证此类被SpringBoot扫描,完成Sa-Token的自定义权限验证扩展 
    public class StpInterfaceImpl implements StpInterface {
    
        /**
         * 返回一个账号所拥有的权限码集合 
         */
        @Override
        public List<String> getPermissionList(Object loginId, String loginType) {
            // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询权限
            List<String> list = new ArrayList<String>();    
            list.add("101");
            list.add("user-add");
            list.add("user-delete");
            list.add("user-update");
            list.add("user-get");
            list.add("article-get");
            return list;
        }
    
        /**
         * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)
         */
        @Override
        public List<String> getRoleList(Object loginId, String loginType) {
            // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询角色
            List<String> list = new ArrayList<String>();    
            list.add("admin");
            list.add("super-admin");
            return list;
        }
    
    }
    
    

4.2权限认证

  • 告诉了sa-token用户所拥有的权限或角色后。就可以用以下api来鉴权了

  • // 判断:当前账号是否含有指定权限, 返回true或false
    StpUtil.hasPermission("user-update");        
    
    // 校验:当前账号是否含有指定权限, 如果验证未通过,则抛出异常: NotPermissionException 
    StpUtil.checkPermission("user-update");        
    
    // 校验:当前账号是否含有指定权限 [指定多个,必须全部验证通过]
    StpUtil.checkPermissionAnd("user-update", "user-delete");        
    
    // 校验:当前账号是否含有指定权限 [指定多个,只要其一验证通过即可]
    StpUtil.checkPermissionOr("user-update", "user-delete");        
    
    // 判断:当前账号是否拥有指定角色, 返回true或false
    StpUtil.hasRole("super-admin");        
    
    // 校验:当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException
    StpUtil.checkRole("super-admin");        
    
    // 校验:当前账号是否含有指定角色标识 [指定多个,必须全部验证通过]
    StpUtil.checkRoleAnd("super-admin", "shop-admin");        
    
    // 校验:当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可] 
    StpUtil.checkRoleOr("super-admin", "shop-admin"); 
    

5.路由拦截鉴权

  • 为什么需要路由拦截鉴权?

  • 方法1:每个方法手动调用如上的鉴权api。如果没有权限就不执行。。这个办法侵入性太高

  • 方法2:注解鉴权。。。这个办法同样不太方便。。。需要修改api接口的注解。

  • 方法3:自己动手书写全局拦截器

  • 方法4:sa-token提供的路由拦截鉴权。。这个是比较方便的。。改动比较少。只需要配置相关配置类。基本上所有事情就搞定了。。。

  • 增加如下配置类即可。如下代码注册了一个登录认证拦截器,并且排除了/user/doLogin接口用来开放登录(除了/user/doLogin以外的所有接口都需要登录才能访问)

  • @Configuration
    public class SaTokenConfigure implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // 注册路由拦截器,自定义认证规则 
            registry.addInterceptor(new SaRouteInterceptor((req, res, handler)->{
                // 根据路由划分模块,不同模块不同鉴权 
                SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
                SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
                SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
                SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
                SaRouter.match("/notice/**", r -> StpUtil.checkPermission("notice"));
                SaRouter.match("/comment/**", r -> StpUtil.checkPermission("comment"));
            })).addPathPatterns("/**")
                .excludePathPatterns("/user/doLogin"); 
        }
    }
    
    
  • 在校验函数内不只可以使用 StpUtil.checkPermission("xxx") 进行权限校验,你还可以写任意代码

  • 最重要的是日记记录。。

  • // 登录认证 -- 拦截所有路由,并排除/user/doLogin 用于开放登录 
    SaRouter.match("/**", "/user/doLogin", r -> StpUtil.checkLogin());
    // 角色认证 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证 
    SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin"));
    // 甚至你可以随意的写一个打印语句
    SaRouter.match("/**", r -> System.out.println("----啦啦啦----"));
    // 连缀写法
    SaRouter.match("/**").check(r -> System.out.println("----啦啦啦----"));
    
  • 除了上述示例的 path 路由匹配,还可以根据很多其它特征进行匹配,以下是所有可匹配的特征:

  • // 基础写法样例:匹配一个path,执行一个校验函数 
    SaRouter.match("/user/**").check(r -> StpUtil.checkLogin());
    
    // 根据 path 路由匹配   ——— 支持写多个path,支持写 restful 风格路由 
    SaRouter.match("/user/**", "/goods/**", "/art/get/{id}").check( /* 要执行的校验函数 */ );
    
    // 根据 path 路由排除匹配 
    SaRouter.match("/**").notMatch("*.html", "*.css", "*.js").check( /* 要执行的校验函数 */ );
    
    // 根据请求类型匹配 
    SaRouter.match(SaHttpMethod.GET).check( /* 要执行的校验函数 */ );
    
    // 根据一个 boolean 条件进行匹配 
    SaRouter.match( StpUtil.isLogin() ).check( /* 要执行的校验函数 */ );
    
    // 根据一个返回 boolean 结果的lambda表达式匹配 
    SaRouter.match( r -> StpUtil.isLogin() ).check( /* 要执行的校验函数 */ );
    
    // 多个条件一起使用 
    SaRouter.match(SaHttpMethod.GET).match("/**").check( /* 要执行的校验函数 */ );
    
    // 可以无限连缀下去 
    SaRouter
        .match(SaHttpMethod.GET)
        .match("/admin/**")
        .match("/user/**") 
        .notMatch("/**/*.js")
        .notMatch("/**/*.css")
        // ....
        .check( /* 只有上述所有条件都匹配成功,才会执行最后的check校验函数 */ );
    
    

参考文章

1.sa-token官方文档路由拦截鉴权

相关文章

网友评论

      本文标题:2022-04-19_spring boot 配置sa-toke

      本文链接:https://www.haomeiwen.com/subject/gqbyertx.html