SaToken学习笔记-04

如果有问题,请点击:传送门

角色认证

在sa-token中,角色和权限可以独立验证

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

扩展:NotRoleException 对象可通过 getLoginKey() 方法获取具体是哪个 StpLogic 抛出的异常

源码解析

- StpUtil.hasRole()

实现了当前账号是否含有指定角色标识, 返回true或false

/**
* 当前账号是否含有指定角色标识, 返回true或false
* @param role 角色标识
* @return 是否含有指定角色标识
*/
public static boolean hasRole(String role) {
return stpLogic.hasRole(role);
}

调用了stpLogic.hasRole()方法并将role传入

/**
* 当前账号是否含有指定角色标识, 返回true或false
* @param role 角色标识
* @return 是否含有指定角色标识
*/
public boolean hasRole(String role) {
return hasRole(getLoginId(), role);
}

将role和获取的当前会话的loginId传入给hasRole方法

/**
* 指定账号id是否含有角色标识, 返回true或false
* @param loginId 账号id
* @param role 角色标识
* @return 是否含有指定角色标识
*/
public boolean hasRole(Object loginId, String role) {
List<String> roleList = SaManager.getStpInterface().getRoleList(loginId, loginKey);
return SaManager.getSaTokenAction().hasElement(roleList, role);
// return !(roleList == null || roleList.contains(role) == false);
}

此方法与学习笔记-03中的hasPermission方法类似,首先获取当前loginId所拥有的所有role的ArrayList,用roleList接收。再掉用SaTokenAction接口中的hasElement方法进行判断。SaTokenActionDefaultImpl实现了此接口并且重写了该方法。

/**
* 指定集合是否包含指定元素(模糊匹配)
*/
@Override
public boolean hasElement(List<String> list, String element) {
// 集合为空直接返回false
if(list == null || list.size() == 0) {
return false;
}
// 遍历匹配
for (String patt : list) {
if(SaFoxUtil.vagueMatch(patt, element)) {
return true;
}
}
// 走出for循环说明没有一个元素可以匹配成功
return false;
}

对每一个在roleList中的元素与role一一比对,如果相同就返回true,否则就返回false


- StpUtil.checkRole()

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

模拟使用场景:

// 当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException
public boolean checkRole(String role){
boolean flag = false;
try {
StpUtil.checkRole(role);
flag=true;
}catch (NotRoleException e){
String key = e.getLoginKey();
System.out.println("key:"+key);
}
return flag;
}

对于该方法:

/**
* 当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException
* @param role 角色标识
*/
public static void checkRole(String role) {
stpLogic.checkRole(role);
}

将role传入给stpLogic.checkRole方法

/**
* 当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException
* @param role 角色标识
*/
public void checkRole(String role) {
if(hasRole(role) == false) {
throw new NotRoleException(role, this.loginKey);
}
}

调用了hasRole方法(在上面的解析中已经解析过)判断返回值是否为false,如果为false则表示不包含指定角色,就抛出NotRoleException异常


什么是NotRoleException异常?
/**
* 没有指定角色标识,抛出的异常
*
* @author kong
*
*/
public class NotRoleException

在这里调用其构造函数

public NotRoleException(String role, String loginKey) {
// 这里到底要不要拼接上loginKey呢?纠结
super("无此角色:" + role);
this.role = role;
this.loginKey = loginKey;
}

- StpUtil.checkRoleAnd()

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

模拟使用场景

//当前账号是否含有指定角色标识 [指定多个,必须全部验证通过]
public boolean checkRoleAnd(String... roles){
boolean flag = false;
try
{
StpUtil.checkRoleAnd(roles);
flag = true;
}catch (NotRoleException e)
{
String key = e.getLoginKey();
System.out.println("key=>"+key);
}
return flag;
}

对于该方法:

/**
* 当前账号是否含有指定角色标识 [指定多个,必须全部验证通过]
* @param roleArray 角色标识数组
*/
public static void checkRoleAnd(String... roleArray){
stpLogic.checkRoleAnd(roleArray);
}

将角色码数组传入stpLogic.checkPermissionAnd()方法

/**
* 当前账号是否含有指定角色标识 [指定多个,必须全部验证通过]
* @param roleArray 角色标识数组
*/
public void checkRoleAnd(String... roleArray){
Object loginId = getLoginId();
List<String> roleList = SaManager.getStpInterface().getRoleList(loginId, loginKey);
for (String role : roleArray) {
if(SaManager.getSaTokenAction().hasElement(roleList, role) == false) {
throw new NotRoleException(role, this.loginKey);
}
}
}

与 checkPermissionAnd()方法类似,首先获取当前对话的loginId并且获得当前对象的所有角色的ArrayList,然后通过循环遍历角色码数组中的所有元素并且调用hasElement方法与roleList中的所有元素一一对比,如果返回值为false就说明其中不包含该角色,就抛出NotRoleExcetipn异常终止。


- StpUtil.checkRoleOr()

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

模拟使用场景:

//当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可]
public boolean checkRoleOr(String... roles){
boolean flag = false;
try{
StpUtil.checkRoleOr(roles);
flag= true;
}catch (NotRoleException e )
{
String key = e.getLoginKey();
String role = e.getRole();
System.out.println("key=>"+key+" role=>"+role);
}
return true;
}

对于该方法:

/**
* 当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可]
* @param roleArray 角色标识数组
*/
public static void checkRoleOr(String... roleArray){
stpLogic.checkRoleOr(roleArray);
}

将角色表示数组传入给stpLogic.checkRoleOr()

/**
* 当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可]
* @param roleArray 角色标识数组
*/
public void checkRoleOr(String... roleArray){
Object loginId = getLoginId();
List<String> roleList = SaManager.getStpInterface().getRoleList(loginId, loginKey);
for (String role : roleArray) {
if(SaManager.getSaTokenAction().hasElement(roleList, role) == true) {
// 有的话提前退出
return;
}
}
if(roleArray.length > 0) {
throw new NotRoleException(roleArray[0], this.loginKey);
}
}

首先获取当前对话的loginId,然后用roleList接受带有所有角色元素的ArrayList,接着通过for对角色标识数组进行遍历,并且调用hasElement方法对遍历的每一个元素判断是否存在于roleList中,只要有一个能够匹配的上就立刻提前退出,否则就判断传入的角色标识数组长度是否大于0,如果大于0则抛出NotRoleException异常。


权限通配符

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

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


如何把权限精确搭到按钮级?

权限精确到按钮级的意思就是指:权限范围可以控制到页面上的每一个按钮是否显示

思路:如此精确的范围控制只依赖后端已经难以完成,此时需要前端进行一定的逻辑判断

在登录时,把当前账号拥有的所有权限码一次性返回给前端
前端将权限码集合保存在localStorage或其它全局状态管理对象中
在需要权限控制的按钮上,使用js进行逻辑判断,例如在vue框架中我们可以使用如下写法:

<button v-if="arr.indexOf('user:delete') > -1">删除按钮</button>

其中:arr是当前用户拥有的权限码数组,user:delete是显示按钮需要拥有的权限码,删除按钮是用户拥有权限码才可以看到的内容

注意:以上写法只为提供一个参考示例,不同框架有不同写法,开发者可根据项目技术栈灵活封装进行调用


前端有了鉴权后端还需要鉴权吗?

需要!前端的鉴权只是一个辅助功能,对于专业人员这些限制都是可以轻松绕过的,为保证服务器安全,无论前端是否进行了权限校验,后端接口都需要对会话请求再次进行权限校验!


End

SaToken学习笔记-04的更多相关文章

  1. 机器学习实战(Machine Learning in Action)学习笔记————04.朴素贝叶斯分类(bayes)

    机器学习实战(Machine Learning in Action)学习笔记————04.朴素贝叶斯分类(bayes) 关键字:朴素贝叶斯.python.源码解析作者:米仓山下时间:2018-10-2 ...

  2. SaToken学习笔记-03

    SaToken学习笔记-03 如果排版有问题,请点击:传送门 核心思想 所谓权限验证,验证的核心就是一个账号是否拥有一个权限码 有,就让你通过.没有?那么禁止访问! 再往底了说,就是每个账号都会拥有一 ...

  3. SaToken学习笔记-02

    SaToken学习笔记-02 如果排版有问题,请点击:传送门 常用的登录有关的方法 - StpUtil.logout() 作用为:当前会话注销登录 调用此方法,其实做了哪些操作呢,我们来一起看一下源码 ...

  4. SaToken学习笔记-01

    SaToken学习笔记-01 SaToken版本为1.18 如果有排版方面的错误,请查看:传送门 springboot集成 根据官网步骤maven导入依赖 <dependency> < ...

  5. Redis:学习笔记-04

    Redis:学习笔记-04 该部分内容,参考了 bilibili 上讲解 Redis 中,观看数最多的课程 Redis最新超详细版教程通俗易懂,来自 UP主 遇见狂神说 10. Redis主从复制 1 ...

  6. xml基础学习笔记04

    今天继续xml学习,主要是:SimpleXML快速解析文档.xml与数组相互转换 .博客中只是简单的做一个学习记录.积累.更加详细的使用方法,可以查看php手册 1.SimpleXML快速解析文档 前 ...

  7. OpenCV 学习笔记 04 深度估计与分割——GrabCut算法与分水岭算法

    1 使用普通摄像头进行深度估计 1.1 深度估计原理 这里会用到几何学中的极几何(Epipolar Geometry),它属于立体视觉(stereo vision)几何学,立体视觉是计算机视觉的一个分 ...

  8. [Golang学习笔记] 04 程序实体1 变量声明

    变量声明: Go语言的程序实体包含:变量.常量.函数.结构体和接口,是一门静态类型的编程语言. (在声明变量或常量的时候,需要指定类型,或者给予足够信息是的Go语言能够推导出类型) Go语言变量的类型 ...

  9. [原创]java WEB学习笔记04:Servlet 简介及第一个Servlet程序(配置注册servlet,生命周期)

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

随机推荐

  1. 整理!企业选择好用的CRM系统的要点(上)

    随着市场经济的发展,对任何行业的企业来说,客户都是非常重要的一个部分.CRM系统帮助企业做到以客户为中心,它可以根据客户的具体要求进行跟进和反馈,在很大程度上提高公司的客户服务水平和客户满意度,进而提 ...

  2. AcWing 220. 最大公约数

    给定整数N,求1<=x,y<=N且GCD(x,y)为素数的数对(x,y)有多少对. GCD(x,y)即求x,y的最大公约数. #include<bits/stdc++.h> u ...

  3. 基于Linux的校园网破解思路和方法

    #思路: ##1. 当校园网断开,只需要重新拨号即可 ##2. 校园网使用两台电脑同时登录时不会立即下线,其中有一段时间间隔 #步骤: ##1. 通过抓包对拨号产生的数据包进行分析,使得可以通过代码来 ...

  4. UI自动化学习笔记- UnitTest单元测试框架详解

    一.UnitTest基本使用 1. UnitTest框架 1.1 什么是框架 说明: 框架英文单词frame 为解决一类事情的功能集合 1.2什么是UnitTest框架 概念:UnitTest是pyt ...

  5. Springboot:SpringBoot2.0整合WebSocket,实现后端数据实时推送!

    一.什么是WebSocket? B/S结构的软件项目中有时客户端需要实时的获得服务器消息,但默认HTTP协议只支持请求响应模式,这样做可以简化Web服务器,减少服务器的负担,加快响应速度,因为服务器不 ...

  6. 数据库表的自增ID createDate和updateDate 用JPA注解代替触发器实现

    对于数据库表的自增ID , createDate和updateDate 等字段,用JPA注解代替触发器实现,效率会高很多. 由于这些属性很多entity都有 可以写成两个基本entity :BaseE ...

  7. MySQL 数据排序 order by

    1.单一字段排序 select * from tablename order by field1 desc; 排序采用order by+排序字段 升序关键字(asc,desc),排序字段可以放多个,多 ...

  8. Pytest学习笔记11-重复执行用例插件pytest-repeat

    前言 我们在平时做测试的时候,经常会遇到一些偶现的bug,通常我们会多次执行来复现此类bug,那么在自动化测试的时候,如何多次运行某个或某些用例呢,我们可以使用pytest-repeat这个插件来帮助 ...

  9. 从2021强网杯的一道题学习docx文件操作

    [强网先锋]寻宝 啊对就是这道题,大佬们都贼快,菜如我还得慢慢整 key1 大佬们都一笔带过,哎,虽然简单,但是也别这么虐我们啊 我来简单写一下吧 <?php header('Content-t ...

  10. 使用Nginx和uwsgi部署Flask项目

    前言   之前用Flask框架开发了一个Python的Web项目,使用Nginx和uWSGI部署起来感觉挺麻烦,过程中还因为对Flask框架的不熟悉,花了好长时间才把应用完全部署起来.下面分享部署成功 ...