基於RBAC實現許可權管理

實習小生發表於2020-11-21

基於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;
    }
}

注意:最後要把攔截器加入到配置裡面

基本上就是這樣了,也可以根據需求再改,關於資料庫表業務會需要加上使用者組表的資訊。

相關文章