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

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官方文档路由拦截鉴权

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容