精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

復雜場景下的權限系統該怎么玩?

jf_ro2CN3Fa ? 來源:芋道源碼 ? 作者:芋道源碼 ? 2022-12-06 10:19 ? 次閱讀


ABAC授權模型

基于屬性的訪問控制(ABAC)- 阿里云IDaaS:

  • https://help.aliyun.com/document_detail/174235.html

ABAC- 百度百科:

  • https://baike.baidu.com/item/abac/3555041?fr=aladdin

個人覺得這兩篇文章已經完美描述了ABAC模型的原理

常用的授權模型

此節摘自基于屬性的訪問控制(ABAC)- 阿里云IDaaS

  • ACL(Access Control List)

在ACL中,包含用戶、資源、資源操作 三個關鍵要素。通過將資源以及資源操作授權給用戶而使用戶獲取對資源進行操作的權限。

  • RBAC(Role-Based Access Control )

是把用戶按角色進行歸類,通過用戶的角色來確定用戶能否針對某項資源進行某項操作。RBAC相對于ACL最大的優勢就是它簡化了用戶與權限的管理,通過對用戶進行分類,使得角色與權限關聯起來,而用戶與權限變成了間接關聯。

  • ABAC(Attribute Base Access Control)

基于屬性的權限控制不同于常見的將用戶通過某種方式關聯到權限的方式,ABAC則是通過動態計算一個或一組屬性來是否滿足某種條件來進行授權判斷(可以編寫簡單的邏輯)。

屬性通常來說分為四類:用戶屬性(如用戶年齡),環境屬性(如當前時間),操作屬性(如讀取)和對象屬性,所以理論上能夠實現非常靈活的權限控制,幾乎能滿足所有類型的需求。

ABAC的訪問控制

基于ABAC訪問控制需要動態計算實體的屬性、操作類型、相關的環境來控制是否有對操作對象的權限,所以在設計的時候需要考慮的條件判斷的靈活性、通用性、易用性,用戶只需要通過web頁面即可配置授權,這需要減少硬編碼似得邏輯變得簡單通用,那么這需要滿足一些運算符來實現。

類型 運算符
算術運算符 +, -, *, /, %, ^, div, mod
關系運算符 <, >, ==, !=, <=, >=, lt, gt, eq, ne, le, ge
邏輯運算符 and, or, not, &&, ||, !
條件 ?:

使用場景

用戶只需要配置 user.age > 20 的條件即可獲得特定的權限。

表達式語言

正如上一節所說的需要對某種條件進行解析那么就需要表達式語言,這讓我想起了Spring Framework@Value注解和MyBatis

//相信很多Javaboy都使用過的吧
@Value("A?B:C")
privateStringA;
"XXX">
<iftest="user!=null">
XXXX
if>

看到這里大家應該大致猜到了ABAC的的核心就是Expression Language(EL),雖然上面的代碼演示是使用Java生態作為演示,但是可以大膽的相信其他的編程語言都是有著自己的EL框架的。

java EL框架列表

  • spring-expression
  • OGNL
  • MVEL
  • JBoss EL

這里就不一一列舉了感興趣可以查看 Java EL生態排名:

https://mvnrepository.com/open-source/expression-languages

SpEL性能

Spring Expression Language (SpEL)官方文檔:

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions

Spring官方文檔摘取 翻譯

Spring Framework 4.1 包含一個基本的表達式編譯器。表達式通常被解釋,這在評估期間提供了很多動態靈活性,但沒有提供最佳性能。對于偶爾的表達式使用,這很好,但是,當由其他組件(如 Spring Integration)使用時,性能可能非常重要,并且沒有真正需要動態性。

SpEL 編譯器旨在滿足這一需求。在求值期間,編譯器生成一個 Java 類,它體現了運行時的表達式行為,并使用該類來實現更快的表達式求值。由于缺少表達式周圍的類型,編譯器在執行編譯時使用在表達式的解釋評估期間收集的信息。例如,它不能純粹從表達式中知道屬性引用的類型,但在第一次解釋評估期間,它會找出它是什么。當然,如果各種表達式元素的類型隨時間發生變化,基于此類派生信息進行編譯可能會在以后造成麻煩。出于這個原因,編譯最適合其類型信息在重復計算時不會改變的表達式。

考慮以下基本表達式:

someArray[0].someProperty.someOtherProperty0.1

由于前面的表達式涉及數組訪問、某些屬性取消引用和數字操作,因此性能提升非常顯著。在一個運行 50000 次迭代的微型基準測試示例中,使用解釋器評估需要 75 毫秒,使用表達式的編譯版本僅需要 3 毫秒。

有關SpEL的性能Spring官方描述說SpEL的性能很棒(個人感覺Spring對自己的測試結果是不是少打了一個0啊,3ms的時間有點無法理解)

基于 Spring Boot + MyBatis Plus + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 視頻教程:https://doc.iocoder.cn/video/

ABAC實踐

本章僅實現ABAC的原理,不會對Spring Security和 Apache Shiro做任何的集成

因為筆者本人是一位Spring boy,所以工程項目會以Spring Boot框架作為基礎,使用其它編程語言的同學可能需要受苦一下了, 大家看懂原理就可以了。

  • Java 8
  • Spring Boot 2.7.6
  • MyBatis Plus 3.5.2
  • MySQL 8.0

數據庫設計

f1b5260c-7508-11ed-8abf-dac502259ad0.png圖片
表名 作用
user 用戶表(ACL和RBAC都有這張表)
user_contribution 用戶的附屬信息 (用戶屬性之類的,不能不一定只有這張表)
permission 權限表達式(ACL和RBAC都有這張表)
abac rbac表達式
abac_permission rbac表達式和權限的綁定關系, o2m
>基于SpringCloudAlibaba+Gateway+Nacos+RocketMQ+Vue&Element實現的后臺管理系統+用戶小程序,支持RBAC動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能
>
>*項目地址://github.com/YunaiV/yudao-cloud>
>*視頻教程//doc.iocoder.cn/video/>

#用戶表
DROPTABLEifEXISTSuser;
CREATETABLEuser(
idbigint(20)NOTNULLCOMMENT'主鍵ID',
namevarchar(30)NULLDEFAULTNULLCOMMENT'姓名',
ageint(11)NULLDEFAULTNULLCOMMENT'年齡',
emailvarchar(50)NULLDEFAULTNULLCOMMENT'郵箱',
PRIMARYKEY(id)
);
#用戶邊緣數據
DROPTABLEifEXISTSuser_contribution;
CREATETABLEuser_contribution(
idbigint(20)NOTNULLCOMMENT'主鍵ID',
user_idbigint(20)NOTNULLCOMMENT'用戶表ID',
repositoryvarchar(100)NOTNULLCOMMENT'倉庫',
PRIMARYKEY(id)
);
#權限表
DROPTABLEifEXISTSpermission;
CREATETABLEpermission(
idbigint(20)NOTNULLCOMMENT'主鍵ID',
permissionvarchar(100)NOTNULLCOMMENT'權限名稱',
PRIMARYKEY(id)
);
#abac表達式表
DROPTABLEifEXISTSabac;
CREATETABLEabac(
idbigint(20)NOTNULLCOMMENT'主鍵ID',
expressionvarchar(100)NOTNULLCOMMENT'abac表達式',
PRIMARYKEY(id)
);
#abac表和權限表的關聯表,o2m
DROPTABLEifEXISTSabac_permission;
CREATETABLEabac_permission(
idbigint(20)NOTNULLCOMMENT'主鍵ID',
abac_idbigint(20)NOTNULLCOMMENT'abac表ID',
permission_idbigint(20)NOTNULLCOMMENT'permission表ID',
PRIMARYKEY(id)
);

java程序

因為篇幅問題, 只會使用必要的代碼, 代碼文件結構

|src
||test
|||java
||||plus.wcj.abac.AbacApplicationTests.java測試類代碼
||main
|||resources
||||application.yml
||||db
|||||schema-h2.sql//DDL
|||||data-h2.sql//DML
|||java
||||plus.wcj.abac
|||||||AbacApplication.java//SpringBoot啟動類
|||||||security
||||||||MetadataCustomizer.java//自定義user信息
||||||||SecurityContext.java//Security上下文
|||||||entity
||||||||Abac.java
||||||||User.java
|||||||dao
||||||||UserDao.java
||||||||AbacDao.java
|||||||service
||||||||UserService.java
||||||||AbacService.java
|pom.xml

crud代碼

pom.xml



org.springframework.boot
spring-boot-starter



org.springframework.boot
spring-boot-starter-test
test



com.baomidou
mybatis-plus-boot-starter
3.5.2



mysql
mysql-connector-java



org.projectlombok
lombok
compile


entity類

/**
*@authorchangjinwei(魏昌進)
*@since2022/11/26
*/
@Data
publicclassAbac{
privateLongid;
privateStringexpression;

/**expression對應的permissions列表*/
@TableField(exist=false)
privateListpermissions;
}

@Data
publicclassUser{
privateLongid;
privateStringname;
privateIntegerage;
privateStringemail;

/**用戶提交過倉庫*/
@TableField(exist=false)
privateListcontributions=newArrayList<>();

/**存放一些亂七八糟的數據,當然contributions字段也放在這里*/
@TableField(exist=false)
privateMapmetadata=newHashMap<>();
}

dao類

/**
*@authorchangjinwei(魏昌進)
*@since2022/11/26
*/
@Mapper
publicinterfaceAbacDaoextendsBaseMapper<Abac>{

/**獲取abacId關聯權限*/
@Select("SELECTp.permission
"+
"FROMabac_permissionapLEFTJOINpermissionpONp.id=ap.permission_id
"+
"WHEREap.abac_id=#{abacId}")
ListselectPermissions(LongabacId);

}

/**
*@authorchangjinwei(魏昌進)
*@since2022/11/26
*/
@Mapper
publicinterfaceUserDaoextendsBaseMapper<User>{

/**獲取用戶的倉庫信息*/
@Select("SELECTrepositoryFROMuser_contributionWHEREuser_id=#{userId}")
ListselectRepository(@Param("userId")LonguserId);
}

service類

/**
*@authorchangjinwei(魏昌進)
*@since2022/11/26
*/
@Service
@RequiredArgsConstructor
publicclassAbacService{
privatefinalAbacDaoabacDao;

/**獲取abac表達式詳細信息列表*/
publicListgetAll(){
Listabacs=abacDao.selectList(null);
for(Abacabac:abacs){
Listpermissions=abacDao.selectPermissions(abac.getId());
abac.setPermissions(permissions);
}
returnabacs;
}
}


/**
*@authorchangjinwei(魏昌進)
*@since2022/11/26
*/
@Service
@RequiredArgsConstructor
publicclassUserService{
privatefinalUserDaouserDao;

/**根據userId獲取用戶詳細信息*/
publicUserget(LonguserId){
Useruser=userDao.selectById(userId);
Listrepository=userDao.selectRepository(userId);
user.setContributions(repository);
returnuser;
}
}

security上下文

/**
*自定義用戶元數據用于獲取一些實體的屬性、操作類型、相關的環境
*
*@authorchangjinwei(魏昌進)
*@since2022/11/26
*/
publicinterfaceMetadataCustomizer{

/**自定義用戶元數據*/
voidcustomize(Useruser);
}

/**
*解析abac表達式
*
*@authorchangjinwei(魏昌進)
*@since2022/11/26
*/
@Component
publicclassSecurityContext{
/**SpEL表達式解析器*/
privatefinalExpressionParserexpressionParser=newSpelExpressionParser();

/**
*解析abac表達式
*@paramuser用戶詳細信息
*@paramabacsabac表達式詳細信息集合
*@returnexpressions集合,將這個結果集存放到SpringSecurity或者ApacheAPISIX的userDetail上下文中
*/
publicListrbacPermissions(Useruser,Listabacs){
returnthis.rbacPermissions(user,abacs,Collections.emptyList());
}

/**
*解析abac表達式
*@paramuser用戶詳細信息
*@paramabacsabac表達式詳細信息集合
*@parammetadataCustomizers自定義用戶元數據用于獲取一些實體的屬性、操作類型、相關的環境
*@returnexpressions集合,將這個結果集存放到SpringSecurity或者ApacheAPISIX的userDetail上下文中
*/
publicListrbacPermissions(Useruser,Listabacs,ListmetadataCustomizers){
//處理自定義元數據
metadataCustomizers.forEach(metadataCustomizer->metadataCustomizer.customize(user));

Listexpressions=newArrayList<>();
for(Abacabac:abacs){
//解析表達式的求值器
Expressionexpression=expressionParser.parseExpression(abac.getExpression());
//創建環境上下文
EvaluationContextcontext=newStandardEvaluationContext(user);
//獲取expression的結果
if(expression.getValue(context,boolean.class)){
expressions.addAll(abac.getPermissions());
}
}
returnexpressions;
}

}

測試類

/**
*@authorchangjinwei(魏昌進)
*@since2022/11/26
*/
@SpringBootTest
classAbacApplicationTests{

@Autowired
privateUserServiceuserService;

@Autowired
privateAbacServiceabacService;

@Autowired
privateSecurityContextsecurityContext;

/**獲取不同用戶的abac權限*/
@Test
voidtestRbac(){
Useruser=userService.get(1L);
Listrbac=abacService.getAll();
Listpermissions=securityContext.rbacPermissions(user,rbac);
System.out.println(permissions);


user=userService.get(2L);
permissions=securityContext.rbacPermissions(user,rbac);
System.out.println(permissions);

user=userService.get(3L);
permissions=securityContext.rbacPermissions(user,rbac);
System.out.println(permissions);

}

/**
*獲取自定義權限
*/
@Test
voidtestMetadataCustomizer(){
Useruser=userService.get(1L);
Listrbac=abacService.getAll();

Listpermissions=securityContext.rbacPermissions(user,rbac);
System.out.println(permissions);

permissions=securityContext.rbacPermissions(user,rbac,getMetadataCustomizer());
System.out.println(permissions);
}

/**模擬網絡ip*/
privateListgetMetadataCustomizer(){
returnnewArrayList(){{
add(user->user.getMetadata().put("ip","192.168.0.1"));
}};
}
}
DELETEFROMuser;
INSERTINTOuser(id,name,age,email)
VALUES(1,'魏昌進',26,'mail@wcj.plus'),
(2,'test',1,'mail1@wcj.plus'),
(3,'admin',1,'mail2@wcj.plus');

DELETEFROMuser_contribution;
INSERTINTOuser_contribution(id,user_id,repository)
VALUES(1,1,'galaxy-sea/spring-cloud-apisix'),
(2,2,'spring-cloud/spring-cloud-commons'),
(3,2,'spring-cloud/spring-cloud-openfeign'),
(4,2,'alibaba/spring-cloud-alibaba'),
(5,2,'Tencent/spring-cloud-tencent'),
(6,2,'apache/apisix-docker');

DELETEFROMpermission;
INSERTINTOpermission(id,permission)
VALUES(1,'githubmerge'),
(2,'githubclose'),
(3,'githubopen'),
(4,'githubcomment');


DELETEFROMabac;
INSERTINTOabac(id,expression)
VALUES(1,'contributions.contains(''galaxy-sea/spring-cloud-apisix'')'),
(2,'name==''admin'''),
(3,'metadata.get(''ip'')==''192.168.0.1''');

DELETEFROMabac_permission;
INSERTINTOabac_permission(id,abac_id,permission_id)
VALUES(1,1,1),

(2,2,1),
(3,2,2),
(4,2,3),
(5,2,4),

(6,3,1),
(7,3,2),
(8,3,3),
(9,3,4);

Spring Security 和 Apache Shiro整合

Spring Security只需要修改攔截器即可在獲取到UserDetailsSecurityContext#rbacPermissions轉換為GrantedAuthority即可

/**
*這里是偽代碼,展示一下大概邏輯
*
*@authorchangjinwei(魏昌進)
*@since2022/04/29
*/
publicclassIamOncePerRequestFilterimplementsOncePerRequestFilter{

@Autowired
privateSecurityContextsecurityContext;

@Autowired
privateAbacServiceabacService;

@Autowired
privateListmetadataCustomizers;

@Autowired
publicvoiddoFilterInternal(HttpServletRequestrequest,HttpServletResponseresponse,FilterChainfilterChain){
UserDetailsuser=toUser();
Listpermissions=securityContext.rbacPermissions(user,abacService.getAll(),metadataCustomizers);
ListabacAuthority=permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
user.getAuthorities().addAll(abacAuthority);
}
}

項目源碼:

  • https://github.com/galaxy-sea/galaxy-blogs/tree/master/code/abac

審核編輯 :李倩


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 編碼
    +關注

    關注

    6

    文章

    915

    瀏覽量

    54651
  • 權限系統
    +關注

    關注

    0

    文章

    6

    瀏覽量

    5941
  • 阿里云
    +關注

    關注

    3

    文章

    922

    瀏覽量

    42780

原文標題:復雜場景下的權限系統該怎么玩?ABAC權限模型幫你搞定它!

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    鴻蒙原生應用元服務開發-位置服務申請權限

    申請位置權限開發指導 場景概述 應用在使用位置服務系統能力前,需要檢查是否已經獲取用戶授權訪問設備位置信息。如未獲得授權,可以向用戶申請需要的位置權限。
    發表于 06-18 15:27

    鴻蒙原生應用元服務-訪問控制(權限)開發應用權限列表二

    接口,用于系統應用完成口令輸入框繪制場景。 權限級別 :system_basic 授權方式 :system_grant ACL使能 :FALSE
    發表于 04-24 15:43

    鴻蒙原生應用元服務-訪問控制(權限)開發應用權限列表一

    授權方式 :system_grant ACL使能 :TRUE ohos.permission.SET_TIME 允許應用修改系統時間。 權限級別 :system_basic 授權方式
    發表于 04-23 14:33

    鴻蒙原生應用元服務-訪問控制(權限)開發校驗環節

    一、場景介紹 應用在提供對外功能服務接口時,可以根據接口涉數據的敏感程度或所涉能力的安全威脅影響,在系統定義的權限列表中權限定義列表選擇合適的權限
    發表于 04-22 17:52

    鴻蒙原生應用元服務-訪問控制(權限)開發概念和使用基本原則

    ATM (AccessTokenManager) 是HarmonyOS上基于AccessToken構建的統一的應用權限管理能力。 默認情況,應用只能訪問有限的系統資源。但某些情況,
    發表于 04-18 15:39

    鴻蒙原生應用元服務-訪問控制(權限)開發等級和類型

    的接口,系統彈框由用戶授權,用戶結合應用運行場景的上下文,識別出應用申請相應敏感權限的合理性,從而做出正確的選擇。 即使用戶向應用授予過請求的權限,應用在調用受此
    發表于 04-17 15:29

    鴻蒙原生應用元服務-訪問控制(權限)開發場景權限聲明

    ** 一、 場景介紹** 應用的APL(Ability Privilege Level)等級分為normal、system_basic和system_core三個等級,默認情況,應用的APL等級
    發表于 04-16 14:40

    一分鐘了解鴻蒙OS 應用權限管理

    HarmonyOS 中所有的應用均在應用沙盒內運行。默認情況,應用只能訪問有限的系統資源,系統負責管理應用對資源的訪問權限。 應用權限管理
    的頭像 發表于 01-26 15:23 ?639次閱讀

    前端大倉monorepo權限設計思路和實現方案

    在 GitLab 未支持文件目錄權限設置之前,對于文件目錄權限的控制主要依賴 Git 的鉤子函數,在代碼提交的時候,對暫存區的變更文件進行識別并做文件權限校驗,流程設計也不怎么復雜,只
    的頭像 發表于 01-12 09:52 ?538次閱讀
    前端大倉monorepo<b class='flag-5'>權限</b>設計思路和實現方案

    oracle系統權限和對象權限的區別

    Oracle系統權限和對象權限是Oracle數據庫中的兩種不同類型的權限控制機制。雖然它們都是用于限制用戶對數據庫進行操作的權限,但它們的作
    的頭像 發表于 12-05 16:21 ?802次閱讀

    Linux文件權限及Makefile

    操作系統)中,文件權限用于控制誰可以對文件進行哪些操作。文件權限權限位組合中表示為一組三位權限字符串。 每個
    的頭像 發表于 11-24 16:06 ?448次閱讀
    Linux文件<b class='flag-5'>權限</b>及Makefile

    虛擬機的root權限在哪里設置

    設置虛擬機的root權限是一項關鍵且復雜的任務,需要在虛擬機的操作系統中進行。下面將詳細介紹如何在不同的虛擬化平臺中設置虛擬機的root權限。 VMware虛擬機的root
    的頭像 發表于 11-23 10:55 ?1w次閱讀

    Linux把目錄權限給指定用戶

    Linux是一個開放源代碼的操作系統,它基于Unix的設計原則,提供了豐富的權限管理功能,允許用戶對系統中的文件和目錄進行精確的控制。在Linux中,每個文件和目錄都有相應的權限,這些
    的頭像 發表于 11-23 10:30 ?7159次閱讀

    linux文件訪問權限怎么設置

    Linux 文件訪問權限是操作系統中一個非常重要的概念。正確地設置文件訪問權限可以保護系統的安全性,防止未經授權的人員對文件進行修改、刪除或執行。本文將詳細介紹 Linux 文件訪問
    的頭像 發表于 11-23 10:20 ?1259次閱讀

    一個輕量級的權限認證框架:Sa-Token

    Java有很多優秀的權限認證框架,如 Apache Shiro 、 Spring Security 等,但是集成起來實在是有些復雜;今天給大家介紹一個輕量級的權限認證框架:Sa-Token,只需引入
    的頭像 發表于 09-30 16:46 ?1564次閱讀
    一個輕量級的<b class='flag-5'>權限</b>認證框架:Sa-Token