基於RBAC實現許可權管理
技術棧:SpringBoot、SpringMVC
RBAC
RBAC資料庫表
主體
編號 | 賬號 | 密碼 |
---|---|---|
001 | admin | 123456 |
資源
編號 | 資源名稱 | 訪問路徑 |
---|---|---|
001 | 查詢使用者列表 | /user/list |
許可權
編號 | 許可權標識 | 許可權名稱 | 資源編號 |
---|---|---|---|
001 | user:list | 檢視使用者列表 | 001 |
角色
角色編號 | 角色名稱 |
---|---|
001 | 管理員 |
使用者角色
編號 | 角色編號 | 使用者編號 |
---|---|---|
001 | 001 | 001 |
角色許可權
編號 | 角色編號 | 許可權編號 |
---|---|---|
001 | 001 | 001 |
可以進行一些合併,優化表數量
將資源表和許可權表進行合併為許可權表
許可權
編號 | 許可權標識 | 許可權名稱 | 資源名稱 | 資源訪問地址 |
---|---|---|---|---|
001 | user:list | 查詢使用者列表 | 使用者列表 | /user/list |
基於角色的訪問控制(Role-Based Access Control)
主要思想就是訪問後臺介面的時候判斷該使用者的角色是否為某某角色,是的話就放行,否則就拒絕訪問。
這裡我用的jwt,token裡儲存的由使用者角色(ADMIN)
實現方式:自定義註解+攔截器
自定義註解
@Target({ElementType.METHOD}) //註解作用域方法上
@Retention(RetentionPolicy.RUNTIME) //編譯器將註解資訊儲存與class檔案中,由JVM讀取
@Documented
public @interface HasRole {
String[] value() default {};
}
SpringMVC攔截器
@Component
public class AccessControlInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
if (handlerMethod.hasMethodAnnotation(HasRole.class)) {
// 從request中獲取token
// 解析token獲取claims
// claims就是個map,直接獲取使用者角色
String role = claims.get("userRole");
String[] hasRole = handlerMethod.getMethodAnnotation(HasRole.class).value();
boolean contains = Arrays.asList(hasRole).contains(role);
if(!contains){
// 不符合條件,可以拋自定義異常,給客戶端提示資訊
return false;
}
}
}
return true;
}
}
注意:最後要把攔截器加入到配置裡面
這種方式很簡單,應對簡單的需求很實用,但是複雜的就行不通了
基於資源的訪問控制(Resource-Based Access Control)
主要思想,由於資源是不會變的,我們給角色或者使用者分配資源許可權後,直接在攔截器裡面進行資源許可權的校驗即可。且有變動的時候基本上不需要改動程式碼。
使用者登入的後把使用者的資源許可權查出來放到redis裡面
實現方式依舊:自定義註解+攔截器
自定義註解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HasResourcePermission {
String value() default "";
}
SpringMVC攔截器
@Component
public class RequestInterceptor implements HandlerInterceptor {
@Resource
private RedisTemplate<String,Object> redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
if (handlerMethod.hasMethodAnnotation(HasResourcePermission.class)) {
String resourcePermissionSign = handlerMethod.getMethodAnnotation(HasResourcePermission.class).value();
Object resourcePermission = redisTemplate.opsForValue().get("resourcePermission");
List<String> resourcePermissionList = (List<String>) resourcePermission;
if (resourcePermissionList.contains(resourcePermissionSign)) {
// 不符合條件,可以拋自定義異常,給客戶端提示資訊
return false;
}
}
}
return true;
}
}
注意:最後要把攔截器加入到配置裡面
基本上就是這樣了,也可以根據需求再改,關於資料庫表業務會需要加上使用者組表的資訊。