使用AOP實現權限攔截校驗

aop的好處就在於它可以只讓你寫一次代碼,然後這些代碼就可以用於容器當中的所有對象,權限攔截校驗是一個表現形式。

那麼,我們要如何實現這個功能?

首先,定義一個註解:

/*
* 被該註釋修飾的方法都會經過切面攔截校驗權限
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Permission {
    PermissionEnum value();
    String msg() default "";
}

這裏有一個PermissionEnum枚舉類,當然可以直接使用String 代替,不過不推薦,其源碼如下:

public enum PermissionEnum {

    LOGIN("login"), // 登錄權限
    CREATE_ADMIN("createAdmin"), // 創建其他管理員的權限
    DASHBOARD_VIEW("dashboardView"), // 查看儀表盤數據的權限
    USER_DATA_VIEW("userDataView"), // 查看用戶數據的權限
    ;
    private String permission;

    PermissionEnum(String permission) {
        this.permission = permission;

    }

    public String getPermission() {
        return permission;
    }
}

這裏,我們控制的權限顆粒度是方法,所以必須使用一個標識符來標誌出每個方法,我們只要將Permission註解加到方法之上,就能被切面所攔截,並進行權限校驗:

@Permission(PermissionEnum.USER_DATA_VIEW)
    public List<User> findAll(Integer page,Integer length){
        Pageable pageable = PageRequest.of(page,length);
        Page<User> userPage = userRepository.findAll(pageable);
        return userPage.stream().collect(Collectors.toList());

    }

上面是一個方法示例:

接下來就是重點了,切入點的編寫:

@Before("pointCut()")
    public void before(JoinPoint joinPoint){
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        var a = method.getAnnotation(Permission.class);

        String msg = null;
        if ("".equals(a.msg())){
            msg = "沒有"+a.value().getPermission()+"權限";
        }else{
            msg = a.msg();
        }
        var permission = adminPermissionService.getCurrentAdminPermission();

        try {
            String methodName = a.value().getPermission();
            methodName = methodName.substring(0,1).toUpperCase()+methodName.substring(1,methodName.length());
            Method method1 = permission.getClass().getMethod("get"+methodName);
            Boolean ret = (Boolean) method1.invoke(permission);
            if (ret == null){
                ErrorUtils.error(msg);
            }

            if (!ret){
                ErrorUtils.error(msg);
            }
        } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            throw new RuntimeException(e.getMessage());
        }

    }

代碼雖然有點長,但做的事並不多,無非就是獲取當前登錄管理員的權限,然後判斷該其切點的權限要求當前管理是否滿足,滿足就繼續運行,否則拋出一個權限錯誤的異常。

當然,這個權限攔截校驗方案是寫死的,也就是說你無法根據實際的情況需要添加或者刪除的相應權限,因爲這是由系統的權限控制方案所限定的,我們權限攔截的目標是方法,不像其他諸如URL的攔截方案,想要修改方法,即攔截目標,就必須修改源碼,所以也就沒有必要做成高度可自定義化的權限方案。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章