spring aop實現權限管理

問題源於項目開發

最近項目中須要作一個權限管理模塊,按照以前同事的作法是在controller層的每一個接口調用以前上作邏輯判斷,這樣作也沒有不妥,可是代碼重複率過高,並且是體力勞動,so,便有了如題所說的使用spring aop作一個切點來實現通用功能的權限管理,這樣也就下降了項目後期開發的可擴展性。git

權限管理的代碼實現與配置文件

在最小的代碼修改程度上,aop無疑是最理想的選擇。項目中有各類權限的複合,相對來講邏輯複雜度比較高,因此一步步來。由於權限涉及到的是後端接口的調用因此樓主選擇在controller層代碼作切面,而切點就是controller中的各個方法塊,對於通用訪問權限,咱們使用execution表達式進行排除。github

只讀管理員權限的實現及切點選擇

對於實現排除通用的controller,樓主採用的是execution表達式邏輯運算。由於只讀管理員擁有全局讀權限,而對於增刪改權限,樓主採用的是使用切點切入是增刪改的方法,so,這個時候規範的方法命名就很重要了。對於各類與只讀管理員進行復合的各類管理員,咱們在代碼中作一下特殊判斷便可。下面是spring aop的配置文件配置方法。web

<!--非法權限拋出異常的spring mvc的處理-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="com.thundersoft.metadata.exception.AccessDeniedException">forward:/auth/readOnly</prop>
        </props>
    </property>
</bean>
    
 <bean id="usersPermissionsAdvice"
          class="com.thundersoft.metadata.aop.UsersPermissionsAdvice"/>
    <aop:config>
        <!--定義切面 -->
        <aop:aspect id="authAspect" ref="usersPermissionsAdvice">
            <!-- 定義切入點 (配置在com.thundersoft.metadata.web.controller下全部的類在調用以前都會被攔截) -->
            <aop:pointcut
                    expression="(execution(* com.thundersoft.metadata.web.controller.*.add*(..)) or execution(* com.thundersoft.metadata.web.controller.*.edit*(..)) or execution(* com.thundersoft.metadata.web.controller.*.del*(..)) or execution(* com.thundersoft.metadata.web.controller.*.update*(..)) or execution(* com.thundersoft.metadata.web.controller.*.insert*(..)) or execution(* com.thundersoft.metadata.web.controller.*.modif*(..))) or execution(* com.thundersoft.metadata.web.controller.*.down*(..))) and ( !execution(* com.thundersoft.metadata.web.controller.FindPasswordController.*(..)) and !execution(* com.thundersoft.metadata.web.controller.SelfServiceController.*(..)) and !execution(* com.thundersoft.metadata.web.controller.HomeController.*(..)) and !execution(* com.thundersoft.metadata.web.controller.UserStatusController.*(..)) and !execution(* com.thundersoft.metadata.web.controller.DashboardController.*(..)) and !execution(* com.thundersoft.metadata.web.controller.MainController.*(..))))"
                    id="authPointCut"/>
            <!--方法被調用以前執行的 -->
            <aop:before method="readOnly"
                        pointcut-ref="authPointCut"/>
        </aop:aspect>
    </aop:config>
複製代碼

只讀管理員權限管理代碼實現

上面說了那麼多,廢話很少說了,下面是對只讀權限與各類複合權限進行控制的切面代碼實現。spring

/**
     * 對只讀管理員以及其複合管理員進行aop攔截判斷.
     * @param joinPoint 切入點.
     * @throws IOException
     */
    public void readOnly(JoinPoint joinPoint) throws IOException {

        /**
         * 獲取被攔截的方法.
         */
        String methodName = joinPoint.getSignature().getName();

        /**
         * 獲取被攔截的對象.
         */
        Object object = joinPoint.getTarget();

        logger.info("權限管理aop,方法名稱{}" + methodName);
        HttpServletRequest request =((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpServletResponse response =((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        String roleFlag = GetLoginUserInfor.getLoginUserRole(request);

        /**
         * 超級管理員
         */
        if (PermissionsLabeled.super_Admin.equals(roleFlag)) {
            return;
        }

        /**
         * 只讀管理員作數據更改權限的判斷
         */
        if (PermissionsLabeled.reader_Admin.equals(roleFlag)) {
            if (methodName.contains("redirectToLogout")) {
                return;
            }
            logger.error("只讀管理員無操做權限!");
            throw new AccessDeniedException("您無權操做!");
        }

        /**
         * 部門管理員,且爲只讀管理員,
         */
        if (PermissionsLabeled.dept_reader_Admin.equals(roleFlag)) {
            if (object instanceof DepartmentController) {
                return;
            }

            if (object instanceof UserController) {
                if (methodName.contains("addAdmin")) {
                    throw new AccessDeniedException("您無權操做!");
                }

                if (methodName.contains("deleteAdmin")) {
                    throw new AccessDeniedException("您無權操做!");
                }

                if (methodName.contains("updateAdmin")) {
                    throw new AccessDeniedException("您無權操做!");
                }
                return;
            }

            if (object instanceof GroupController) {
                return;
            }
            logger.error("部門管理員,且爲只讀管理員無操做權限!");
            throw new AccessDeniedException("您無權操做!");
        }

        /**
         * 應用管理員,且爲只讀管理員
         */
        if (PermissionsLabeled.app_reader_Admin.equals(roleFlag)) {
            if (object instanceof AppController) {
                return;
            }

            if (object instanceof AppPolicyController) {
                return;
            }
            logger.error("應用管理員,且爲只讀管理員無操做權限!");
            throw new AccessDeniedException("您無權操做!");
        }

        /**
         * 部門管理員,且爲應用管理員,且爲只讀管理員
         */
        if (PermissionsLabeled.dept_app_reader_Admin.equals(roleFlag)) {
            if (object instanceof DepartmentController) {
                return;
            }

            if (object instanceof UserController) {
                return;
            }

            if (object instanceof GroupController) {
                return;
            }

            if (object instanceof AppController) {
                return;
            }

            if (object instanceof AppPolicyController) {
                return;
            }
            logger.error("部門管理員,且爲應用管理員,且爲只讀管理員無操做權限");
            throw new AccessDeniedException("您無權操做!");
        }
    }
複製代碼

具備專門功能的管理員權限控制的切點選擇

由於具備專門的管理員權限比較特殊,樓主採用的方式除了通用訪問權限以外的controller全切,特殊狀況在代碼邏輯裏面作實現便可。配置文件代碼以下:express

<aop:config>
        <!--定義切面 -->
        <aop:aspect id="authAspect" ref="usersPermissionsAdvice">
            <!-- 定義切入點 (配置在com.thundersoft.metadata.web.controller下全部的類在調用以前都會被攔截) -->
            <aop:pointcut
                    expression="(execution(* com.thundersoft.metadata.web.controller.*.*(..)) and ( !execution(* com.thundersoft.metadata.web.controller.FindPasswordController.*(..)) and !execution(* com.thundersoft.metadata.web.controller.SelfServiceController.*(..)) and !execution(* com.thundersoft.metadata.web.controller.HomeController.*(..)) and !execution(* com.thundersoft.metadata.web.controller.UserStatusController.*(..)) and !execution(* com.thundersoft.metadata.web.controller.DashboardController.*(..)) and !execution(* com.thundersoft.metadata.web.controller.MainController.*(..))))"
                    id="appAuthPointCut"/>
            <!--方法被調用以前執行的 -->
            <aop:before method="appDeptAuth"
                        pointcut-ref="appAuthPointCut"/>
        </aop:aspect>
    </aop:config>
複製代碼

權限管理的切面代碼實現

/**
     * 對應用管理員以及部門管理員進行aop攔截判斷.
     * @param joinPoint 切入點.
     * @throws IOException
     */
    public void appDeptAuth(JoinPoint joinPoint) throws IOException {
        /**
         * 獲取被攔截的方法.
         */
        String methodName = joinPoint.getSignature().getName();

        /**
         * 獲取被攔截的對象.
         */
        Object object = joinPoint.getTarget();

        logger.info("權限管理aop,方法名稱{}",methodName);
        HttpServletRequest request =((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpServletResponse response =((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        String roleFlag = GetLoginUserInfor.getLoginUserRole(request);

        /**
         * 超級管理員
         */
        if (PermissionsLabeled.super_Admin.equals(roleFlag)) {
            return;
        }

        /**
         * 應用管理員作數據更改權限的判斷
         */
        if (PermissionsLabeled.app_Admin.equals(roleFlag)) {
            if (object instanceof AppController) {
                return;
            }

            if (object instanceof AppPolicyController) {
                return;
            }

            logger.error("應用管理員無操做權限");
            throw new AccessDeniedException("您無權操做!");
        } else if (PermissionsLabeled.dept_Admin.equals(roleFlag)) {
            if (object instanceof DepartmentController) {
                return;
            }

            if (object instanceof UserController) {
                return;
            }

            if (object instanceof GroupController) {
                return;
            }
            if ("getAllDepartments".equals(methodName)) {
                return;
            }
            logger.error("應用管理員無操做權限");
            throw new AccessDeniedException("您無權操做!");
        } else {
            return;
        }
    }
複製代碼

自定義權限非法異常代碼

/**
 * @author wuhf0703@thundersoft.com
 * @date 2017/12/12
 */
public class AccessDeniedException extends RuntimeException {

    /**
     * Constructs a <code>AccessDeniedException</code> with the specified message.
     *
     * @param msg the detail message.
     */
    public AccessDeniedException(String msg) {
        super(msg);
    }

    /**
     * Constructs a {@code AccessDeniedException} with the specified message and root cause.
     *
     * @param msg the detail message.
     * @param t root cause
     */
    public AccessDeniedException(String msg, Throwable t) {
        super(msg, t);
    }
}

複製代碼

博客首發連接後端

相關文章
相關標籤/搜索