簡介
RBAC是基于角色的權(quán)限控制,讓角色綁定權(quán)限橡卤,用戶綁定角色,它們之間都是多對多的關(guān)系损搬。
用戶和角色好理解碧库,但是權(quán)限究竟應(yīng)該怎么標示,可以抽象成一句話來概括:誰在什么地方能進行什么操作巧勤。
什么地方可以對應(yīng)模塊嵌灰,什么操作可以對應(yīng)模塊開放的接口。
數(shù)據(jù)庫設(shè)計
權(quán)限控制分為三個實體颅悉,角色沽瞭、用戶、模塊
簡要的E-R模型
user和passport分開是為了邏輯更清晰剩瓶,因為登陸只需要驗證賬號密碼等賬號相關(guān)的信息驹溃,可以只對一個表進行操作。
賬號和角色多對多延曙,沒問題豌鹤。
角色、模塊枝缔、操作共同構(gòu)成的關(guān)系就是權(quán)限布疙。表述了:誰(角色)在什么地方(模塊)能夠做什么(操作)
使用aop做全局的權(quán)限控制
關(guān)于可配置的思考
角色和權(quán)限的綁定肯定需要動態(tài)的,也就是可以運行時配置的。
但是模塊和操作的新增不一定能夠做到可配置灵临,因為操作和模塊都是需要對應(yīng)到代碼的截型。比如,需要新增一個訂單管理模塊儒溉,肯定是需要編碼宦焦,編寫相應(yīng)接口,然后才能夠工作的睁搭。必須要先有這個模塊的實現(xiàn)赶诊,才能在數(shù)據(jù)庫中進行配置訪問權(quán)限笼平,這是理所當(dāng)然的园骆。因此,模塊的新增不必在程序運行時配置寓调。
還有一個問題锌唾,怎么將數(shù)據(jù)庫中action表的記錄對應(yīng)到代碼的方法上。我采用了注解夺英。
權(quán)限注解:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Privilege {
ModuleType moduleType();//模塊
ActionType actionType();//操作
}
操作:
public enum ActionType {
ADD(1),EDIT(2),DEL(3),SHOW(4);
int value;//對應(yīng)數(shù)據(jù)庫中操作的id
ActionType(int value){
this.value = value;
}
public int getValue(){
return value;
}
}
數(shù)據(jù)庫中存儲的操作記錄:
模塊:
public enum ModuleType {
PRIVILEGE_MANAGEMENT(1);
int value;
ModuleType(int value){
this.value = value;
}
public int getValue(){
return value;
}
}
數(shù)據(jù)庫中的模塊記錄:
全局權(quán)限控制的切面:
@Around("@annotation(privilege)")
public Object checkPrivilege(ProceedingJoinPoint joinPoint
, Privilege privilege) throws Throwable {
SessionUser user = (SessionUser) SessionUtil.getCurrentSession().getAttribute("user");
if (user==null){
throw new RuntimeException("haven't login yet!");
}
if(!privilegeService.checkPrivilege(user
, privilege.moduleType().getValue()
, privilege.actionType().getValue())){
throw new RuntimeException("access denied!");
}
return joinPoint.proceed();
}
攔截注解@Privilege晌涕,根據(jù)其提供的模塊信息和操作信息進行權(quán)限校驗。
使用:
編寫模塊痛悯,并通過注解標識其方法對應(yīng)的操作:
@RestController
public class TestController {
@RequestMapping("add")
@Privilege(moduleType = ModuleType.PRIVILEGE_MANAGEMENT
,actionType = ActionType.ADD)
public Object testAdd(){
return "add ok!";
}
}
配置權(quán)限:
actions字段適當(dāng)冗余減少記錄數(shù)余黎。
權(quán)限控制流程:
訪問testAdd方法,被切面攔截载萌,進入checkPrivilege方法惧财,在該方法中,通過testAdd方法上的@Privilege注解扭仁,獲取到testAdd方法對應(yīng)的操作和模塊垮衷,同時獲取當(dāng)前sesssion會話中的用戶角色,根據(jù)角色乖坠、模塊查詢數(shù)據(jù)庫搀突,獲取到能夠進行的操作,與當(dāng)前testAdd方法的操作比對熊泵,從而確定是否有權(quán)訪問此方法仰迁。比對成功,繼續(xù)執(zhí)行顽分,比對失敗徐许,拋出權(quán)限不足異常。
對于這種實現(xiàn)的優(yōu)劣分析
優(yōu)點很明顯怯邪,能夠做到角色權(quán)限可配置绊寻,用戶角色可配置,而且也減小了權(quán)限邏輯和業(yè)務(wù)邏輯的耦合度,需要調(diào)用權(quán)限控制澄步,只需要加上權(quán)限控制的注解即可冰蘑。
缺點也很明顯,無法做到模塊和操作的動態(tài)增加村缸,因為模塊和操作都是硬編碼的祠肥,每次新增模塊或者新增操作,勢必要經(jīng)過修改代碼梯皿、編譯仇箱、重新運行的過程。
demo:
https://github.com/DangerousPrayer/sso-server
僅作參考东羹。