SaToken學習筆記-04
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
/**
* 指定集合是否包含指定元素(模糊匹配)
*/
@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
- 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
許可權萬用字元
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是顯示按鈕需要擁有的許可權碼,刪除按鈕是使用者擁有許可權碼才可以看到的內容
注意:以上寫法只為提供一個參考示例,不同框架有不同寫法,開發者可根據專案技術棧靈活封裝進行呼叫
前端有了鑑權後端還需要鑑權嗎?
需要!前端的鑑權只是一個輔助功能,對於專業人員這些限制都是可以輕鬆繞過的,為保證伺服器安全,無論前端是否進行了許可權校驗,後端介面都需要對會話請求再次進行許可權校驗!