SpringBoot集成Sa 您所在的位置:网站首页 机顶盒正在鉴权验证中 SpringBoot集成Sa

SpringBoot集成Sa

2023-05-21 12:22| 来源: 网络整理| 查看: 265

1 添加依赖

   cn.dev33

   sa-token-spring-boot-starter

   1.28.0

2 配置文件

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

3.1 登录与注销

// 标记当前会话登录的账号id

// 建议的参数类型:long | int | String, 不可以传入复杂类型,如:User、Admin等等

StpUtil.login(Object id);    

// 当前会话注销登录

StpUtil.logout();

// 获取当前会话是否已经登录,返回true=已登录,false=未登录

StpUtil.isLogin();

// 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`

StpUtil.checkLogin();

3.2 会话查询

// 获取当前会话账号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 权限认证

4.1 设置权限码和角色

import java.util.ArrayList;

import java.util.List;

import org.springframework.stereotype.Component;

import cn.dev33.satoken.stp.StpInterface;

/**

* 自定义权限验证接口扩展

*/

@Component

public class StpInterfaceImpl implements StpInterface {

   /**

    * 返回一个账号所拥有的权限码集合

    */

   @Override

   public List getPermissionList(Object loginId, String loginType) {

       // 模拟权限码

       List list = new ArrayList();    

       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 getRoleList(Object loginId, String loginType) {

       // 模拟角色

       List list = new ArrayList();    

       list.add("admin");

       list.add("super-admin");

       return list;

   }

}

4.2 权限认证

// 判断:当前账号是否含有指定权限, 返回true或false

StpUtil.hasPermission("user-update");        

// 校验:当前账号是否含有指定权限, 如果验证未通过,则抛出异常: NotPermissionException

StpUtil.checkPermission("user-update");        

// 校验:当前账号是否含有指定权限 [指定多个,必须全部验证通过]

StpUtil.checkPermissionAnd("user-update", "user-delete");        

// 校验:当前账号是否含有指定权限 [指定多个,只要其一验证通过即可]

StpUtil.checkPermissionOr("user-update", "user-delete");        

4.3 角色认证

// 判断:当前账号是否拥有指定角色, 返回true或false

StpUtil.hasRole("super-admin");        

// 校验:当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException

StpUtil.checkRole("super-admin");        

// 校验:当前账号是否含有指定角色标识 [指定多个,必须全部验证通过]

StpUtil.checkRoleAnd("super-admin", "shop-admin");        

// 校验:当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可]

StpUtil.checkRoleOr("super-admin", "shop-admin");        

4.4 权限通配符

Sa-Token允许你根据通配符指定泛权限,例如当一个账号拥有user*的权限时,user-add、user-delete、user-update都将匹配通过 。

// 当拥有 user* 权限时

StpUtil.hasPermission("user-add");        // true

StpUtil.hasPermission("user-update");     // true

StpUtil.hasPermission("art-add");         // false

// 当拥有 *-delete 权限时

StpUtil.hasPermission("user-add");        // false

StpUtil.hasPermission("user-delete");     // true

StpUtil.hasPermission("art-delete");      // true

// 当拥有 *.js 权限时

StpUtil.hasPermission("index.js");        // true

StpUtil.hasPermission("index.css");       // false

StpUtil.hasPermission("index.html");      // false

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

5 踢人下线

5.1 强制注销

StpUtil.logout(10001);                    // 强制指定账号注销下线

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

StpUtil.logoutByTokenValue("token");      // 强制指定 Token 注销下线

5.2 踢人下线

StpUtil.kickout(10001);                    // 将指定账号踢下线

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

StpUtil.kickoutByTokenValue("token");      // 将指定 Token 踢下线

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

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

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

5.3 账号封禁

对于违规账号,有时候我们仅仅将其踢下线还是远远不够的,我们还需要对其进行账号封禁防止其再次登录 。

// 封禁指定账号

// 参数一:账号id

// 参数二:封禁时长,单位:秒  (86400秒=1天,此值为-1时,代表永久封禁)

StpUtil.disable(10001, 86400);

// 获取指定账号是否已被封禁 (true=已被封禁, false=未被封禁)

StpUtil.isDisable(10001);

// 获取指定账号剩余封禁时间,单位:秒

StpUtil.getDisableTime(10001);

// 解除封禁

StpUtil.untieDisable(10001);

注意

对于正在登录的账号,对其账号封禁时并不会使其立刻注销

如果需要将其封禁后立即掉线,可采取先踢再封禁的策略,例如:

// 先踢下线

StpUtil.kickout(10001);

// 再封禁账号 封一天1

StpUtil.disable(10001, 86400);

6 注解式鉴权

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

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

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

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

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

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

Sa-Token使用全局拦截器完成注解鉴权功能,为了不为项目带来不必要的性能负担,拦截器默认处于关闭状态

因此,为了使用注解鉴权,你必须手动将Sa-Token的全局拦截器注册到你项目中。

6.1 注册拦截器

注:注册拦截器方式的注解鉴权只能加在controller层。

@Configuration

public class SaTokenConfigure implements WebMvcConfigurer {

   // 注册Sa-Token的注解拦截器,打开注解式鉴权功能

   @Override

   public void addInterceptors(InterceptorRegistry registry) {

       // 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关)

       registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");    

   }

}

6.2 使用注解鉴权

// 登录认证:只有登录之后才能进入该方法

@SaCheckLogin                        

@RequestMapping("info")

public String info() {

   return "查询用户信息";

}

// 角色认证:必须具有指定角色才能进入该方法

@SaCheckRole("super-admin")        

@RequestMapping("add")

public String add() {

   return "用户增加";

}

// 权限认证:必须具有指定权限才能进入该方法

@SaCheckPermission("user-add")        

@RequestMapping("add")

public String add() {

   return "用户增加";

}

// 二级认证:必须二级认证之后才能进入该方法

@SaCheckSafe()        

@RequestMapping("add")

public String add() {

   return "用户增加";

}

// Http Basic 认证:只有通过 Basic 认证后才能进入该方法

@SaCheckBasic(account = "sa:123456")

@RequestMapping("add")

public String add() {

   return "用户增加";

}

注:以上注解都可以加在类上,代表为这个类所有方法进行鉴权 。

6.3 设定校验模式

@SaCheckRole与@SaCheckPermission注解可设置校验模式,例如:

// 注解式鉴权:只要具有其中一个权限即可通过校验

@RequestMapping("atJurOr")

@SaCheckPermission(value = {"user-add", "user-all", "user-delete"}, mode = SaMode.OR)        

public AjaxJson atJurOr() {

   return AjaxJson.getSuccessData("用户信息");

}

mode有两种取值:

SaMode.AND, 标注一组权限,会话必须全部具有才可通过校验。

SaMode.OR, 标注一组权限,会话只要具有其一即可通过校验。

6.4 角色权限双重"or校验"

// 注解式鉴权:只要具有其中一个权限即可通过校验

@RequestMapping("userAdd")

@SaCheckPermission(value = "user-add", orRole = "admin")        

public AjaxJson userAdd() {

   return AjaxJson.getSuccessData("用户信息");

}

orRole 字段代表权限认证未通过时的次要选择,两者只要其一认证成功即可通过校验,其有三种写法:

写法一:orRole = "admin",代表需要拥有角色 admin 。

写法二:orRole = {"admin", "manager", "staff"},代表具有三个角色其一即可。

写法三:orRole = {"admin, manager, staff"},代表必须同时具有三个角色。

6.5 在业务层使用注解鉴权

使用拦截器模式,只能在Controller层进行注解鉴权,如需在任意层级使用注解鉴权,请参考:AOP注解鉴权

7 路由拦截鉴权

需求:项目中所有接口均需要登录认证,只有’登录接口’本身对外开放 。

7.1 注册路由拦截器

建配置类

@Configuration

public class SaTokenConfigure implements WebMvcConfigurer {

   // 注册拦截器

   @Override

   public void addInterceptors(InterceptorRegistry registry) {

       // 注册Sa-Token的路由拦截器

       registry.addInterceptor(new SaRouteInterceptor())

           .addPathPatterns("/**")

           .excludePathPatterns("/user/doLogin");

   }

}

以上代码,我们注册了一个登录认证拦截器,并且排除了/user/doLogin接口用来开放登录(除了/user/doLogin以外的所有接口都需要登录才能访问)。

7.2 校验函数详解

可以使用函数式编程自定义认证规则,例如:

@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("/**");

   }

}

SaRouter.match() 匹配函数有两个参数:

参数一:要匹配的path路由。

参数二:要执行的校验函数。

在校验函数内不只可以使用 StpUtil.checkPermission("xxx") 进行权限校验,你还可以写任意代码,例如:

@Configuration

public class SaTokenConfigure implements WebMvcConfigurer {

   // 注册Sa-Token的拦截器

   @Override

   public void addInterceptors(InterceptorRegistry registry) {

       // 注册路由拦截器,自定义认证规则

       registry.addInterceptor(new SaRouteInterceptor((req, res, handler) -> {

           // 登录认证 -- 拦截所有路由,并排除/user/doLogin 用于开放登录

           SaRouter.match("/**", "/user/doLogin", r -> StpUtil.checkLogin());

           // 角色认证 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证

           SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin"));

           // 权限认证 -- 不同模块认证不同权限

           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"));

           // 甚至你可以随意的写一个打印语句

           SaRouter.match("/**", r -> System.out.println("----啦啦啦----"));

           // 连缀写法

           SaRouter.match("/**").check(r -> System.out.println("----啦啦啦----"));

       })).addPathPatterns("/**");

   }

}

7.3 匹配特征详解

// 基础写法样例:匹配一个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校验函数 */ );

7.4 提前退出匹配链

使用 SaRouter.stop() 可以提前退出匹配链,例:

registry.addInterceptor(new SaRouteInterceptor((req, res, handler) -> {

   SaRouter.match("/**").check(r -> System.out.println("进入1"));

   SaRouter.match("/**").check(r -> System.out.println("进入2")).stop();

   SaRouter.match("/**").check(r -> System.out.println("进入3"));

})).addPathPatterns("/**");

如上示例,代码运行至第2条匹配链时,会在stop函数处提前退出整个匹配函数,从而忽略掉剩余的所有match匹配。

除了stop()函数,SaRouter还提供了 back() 函数,用于:停止匹配,结束执行,直接向前端返回结果。

// 执行back函数后将停止匹配,也不会进入Controller,而是直接将 back参数 作为返回值输出到前端

SaRouter.match("/user/back").back("参数");

stop() 与 back() 函数的区别在于:

SaRouter.stop() 会停止匹配,进入Controller。

SaRouter.back() 会停止匹配,直接返回结果到前端。

7.5 使用free打开一个独立的作用域

// 进入 free 独立作用域

SaRouter.match("/**").free(r -> {

   SaRouter.match("/a/**").check(/* --- */);

   SaRouter.match("/a/**").check(/* --- */).stop();

   SaRouter.match("/a/**").check(/* --- */);

});

// 执行 stop() 函数跳出 free 后继续执行下面的 match 匹配

SaRouter.match("/**").check(/* --- */);

free() 的作用是:打开一个独立的作用域,使内部的 stop() 不再一次性跳出整个 Auth 函数,而是仅仅跳出当前 free 作用域。

8 Session会话

Session是会话中专业的数据缓存组件,通过 Session 我们可以很方便的缓存一些高频读写数据,提高程序性能,例如:

// 在登录时缓存user对象

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

// 然后我们就可以在任意处使用这个user对象

SysUser user = (SysUser) StpUtil.getSession().get("user")

在 Sa-Token 中,Session 分为三种,分别是:

User-Session: 指的是框架为每个 账号id 分配的 Session

Token-Session: 指的是框架为每个 token 分配的 Session

Custom-Session: 指的是以一个 特定的值 作为SessionId,来分配的 Session

有关User-Session与Token-Session的详细区别,请参考:Session模型详解

8.1 User-Session

有关账号Session的API如下:

// 获取当前账号id的Session (必须是登录后才能调用)

StpUtil.getSession();

// 获取当前账号id的Session, 并决定在Session尚未创建时,是否新建并返回

StpUtil.getSession(true);

// 获取账号id为10001的Session

StpUtil.getSessionByLoginId(10001);

// 获取账号id为10001的Session, 并决定在Session尚未创建时,是否新建并返回

StpUtil.getSessionByLoginId(10001, true);

// 获取SessionId为xxxx-xxxx的Session, 在Session尚未创建时, 返回null

StpUtil.getSessionBySessionId("xxxx-xxxx");

8.2 Token-Session

有关令牌Session的API如下:

// 获取当前token的专属Session

StpUtil.getTokenSession();

// 获取指定token的专属Session

StpUtil.getTokenSessionByToken(token);

在未登录状态下是否可以获取Token-Session?这取决于你配置的tokenSessionCheckLogin值是否为false,详见:框架配置

8.3 自定义Session

自定义Session指的是以一个特定的值作为SessionId来分配的Session, 借助自定义Session,你可以为系统中的任意元素分配相应的session

例如以商品id作为key为每个商品分配一个Session,以便于缓存和商品相关的数据,其相关API如下:

// 查询指定key的Session是否存在

SaSessionCustomUtil.isExists("goods-10001");

// 获取指定key的Session,如果没有,则新建并返回

SaSessionCustomUtil.getSessionById("goods-10001");

// 获取指定key的Session,如果没有,第二个参数决定是否新建并返回  

SaSessionCustomUtil.getSessionById("goods-10001", false);  

// 删除指定key的Session

SaSessionCustomUtil.deleteSessionById("goods-10001");

8.4 Session相关操作

// 返回此Session的id

session.getId();                          

// 返回此Session的创建时间 (时间戳)

session.getCreateTime();                  

// 在Session上获取一个值

session.getAttribute('name');            

// 在Session上获取一个值,并指定取不到值时返回的默认值

session.getAttribute('name', 'zhang');    

// 在Session上写入一个值

session.setAttribute('name', 'zhang');    

// 在Session上移除一个值

session.removeAttribute('name');          

// 清空此Session的所有值

session.clearAttribute();                

// 获取此Session是否含有指定key (返回true或false)

session.containsAttribute('name');        

// 获取此Session会话上所有key (返回Set)

session.attributeKeys();                  

// 返回此Session会话上的底层数据对象(如果更新map里的值,请调用session.update()方法避免产生脏数据)

session.getDataMap();                    

// 将这个Session从持久库更新一下

session.update();                        

// 注销此Session会话 (从持久库删除此Session)

session.logout();                        

8.5 类型转换API

由于Session存取值默认的类型都是Object,因此我们通常会写很多不必要类型转换代码

为了简化操作,Sa-Token自v1.15.0封装了存取值API的类型转换,你可以非常方便的调用以下方法:

// 写值

session.set("name", "zhang");

// 写值 (只有在此key原本无值的时候才会写入)

session.setDefaultValue("name", "zhang");

// 取值

session.get("name");

// 取值 (指定默认值)

session.get("name", "");

// 取值 (转String类型)

session.getString("name");

// 取值 (转int类型)

session.getInt("age");

// 取值 (转long类型)

session.getLong("age");

// 取值 (转double类型)

session.getDouble("result");

// 取值 (转float类型)

session.getFloat("result");

// 取值 (指定转换类型)

session.getModel("key", Student.class);

// 取值 (指定转换类型, 并指定值为Null时返回的默认值)

session.getModel("key", Student.class, );

// 是否含有某个key

session.has("key");

8.6 Sesion环境隔离说明

有同学经常会把 SaSession 与 HttpSession 进行混淆,例如:

@PostMapping("/resetPoints")

public void reset(HttpSession session) {

   // 在HttpSession上写入一个值

   session.setAttribute("name", 66);

   // 在SaSession进行取值

   System.out.println(StpUtil.getSession().getAttribute("name"));    // 输出null

}

要点:

SaSession 与 HttpSession 没有任何关系,在HttpSession上写入的值,在SaSession中无法取出。

HttpSession并未被框架接管,在使用Sa-Token时,请在任何情况下均使用SaSession,不要使用HttpSession。

9 框架配置

框架配置

10 集成Redis

集成Redis

11 前后端分离

前后端分离

12 自定义Token风格

12.1 内置风格

Sa-Token默认的token生成策略是uuid风格,其模样类似于:623368f0-ae5e-4475-a53f-93e4225f16ae

如果你对这种风格不太感冒,还可以将token生成设置为其他风格

怎么设置呢?只需要在yml配置文件里设置 sa-token.token-style=风格类型 即可,其有多种取值:

// 1. token-style=uuid    —— uuid风格 (默认风格)

"623368f0-ae5e-4475-a53f-93e4225f16ae"

// 2. token-style=simple-uuid    —— 同上,uuid风格, 只不过去掉了中划线

"6fd4221395024b5f87edd34bc3258ee8"

// 3. token-style=random-32    —— 随机32位字符串

"qEjyPsEA1Bkc9dr8YP6okFr5umCZNR6W"

// 4. token-style=random-64    —— 随机64位字符串

"v4ueNLEpPwMtmOPMBtOOeIQsvP8z9gkMgIVibTUVjkrNrlfra5CGwQkViDjO8jcc"

// 5. token-style=random-128    —— 随机128位字符串

"nojYPmcEtrFEaN0Otpssa8I8jpk8FO53UcMZkCP9qyoHaDbKS6dxoRPky9c6QlftQ0pdzxRGXsKZmUSrPeZBOD6kJFfmfgiRyUmYWcj4WU4SSP2ilakWN1HYnIuX0Olj"

// 6. token-style=tik    —— tik风格

"gr_SwoIN0MC1ewxHX_vfCW3BothWDZMMtx__"

12.2 自定义token生成策略

如果觉着以上风格都不是你喜欢的类型,那么还可以自定义token生成策略,来定制化token生成风格

怎么做呢?只需要重写 SaStrategy 策略类的 createToken 算法即可

步骤:

1、在SaTokenConfigure配置类中添加代码:

@Configuration

public class SaTokenConfigure {

   /**

    * 重写 Sa-Token 框架内部算法策略

    */

   @Autowired

   public void rewriteSaStrategy() {

       // 重写 Token 生成策略

       SaStrategy.me.createToken = (loginId, loginType) -> {

           return SaFoxUtil.getRandomString(60);    // 随机60位长度字符串

       };

   }

}

2、再次调用 StpUtil.login(10001)方法进行登录,观察其生成的token样式:

gfuPSwZsnUhwgz08GTCH4wOgasWtc3odP4HLwXJ7NDGOximTvT4OlW19zeLH

13 自定义Token前缀

在某些系统中,前端提交token时会在前面加个固定的前缀,例如:

{

   "satoken": "Bearer xxxx-xxxx-xxxx-xxxx"

}

此时后端如果不做任何特殊处理,框架将会把Bearer视为token的一部分,无法正常读取token信息,导致鉴权失败

为此,我们需要在yml中添加如下配置:

sa-token:

   # token前缀

   token-prefix: Bearer

此时 Sa-Token 便可在读取 Token 时裁剪掉 Bearer,成功获取xxxx-xxxx-xxxx-xxxx

注意:

Token前缀 与 Token值 之间必须有一个空格。

一旦配置了 Token前缀,则前端提交token时,必须带有前缀,否则会导致框架无法读取token。

由于Cookie中无法存储空格字符,也就意味配置token前缀后,Cookie鉴权方式将会失效,此时只能将token提交到header里进行传输。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有