前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >spring aop实现权限管理

spring aop实现权限管理

作者头像
haifeiWu
发布2018-09-11 10:20:12
1.2K0
发布2018-09-11 10:20:12
举报

最近项目中需要做一个权限管理模块,按照之前同事的做法是在controller层的每个接口调用之前上做逻辑判断,这样做也没有不妥,但是代码重复率太高,而且是体力劳动,so,便有了如题所说的使用spring aop做一个切点来实现通用功能的权限管理,这样也就降低了项目后期开发的可扩展性。

权限管理的代码实现与配置文件

在最小的代码修改程度上,aop无疑是最理想的选择。项目中有各种权限的复合,相对来说逻辑复杂度比较高,所以一步步来。因为权限涉及到的是后端接口的调用所以楼主选择在controller层代码做切面,而切点就是controller中的各个方法块,对于通用访问权限,我们使用execution表达式进行排除。

只读管理员权限的实现及切点选择

对于实现排除通用的controller,楼主采用的是execution表达式逻辑运算。因为只读管理员拥有全局读权限,而对于增删改权限,楼主采用的是使用切点切入是增删改的方法,so,这个时候规范的方法命名就很重要了。对于各种与只读管理员进行复合的各种管理员,我们在代码中做一下特殊判断即可。下面是spring aop的配置文件配置方法。

<!--非法权限抛出异常的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>

只读管理员权限管理代码实现

上面说了那么多,废话不多说了,下面是对只读权限与各种复合权限进行控制的切面代码实现。

/**
    * 对只读管理员以及其复合管理员进行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全切,特殊情况在代码逻辑里面做实现即可。配置文件代码如下:

<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);
    }
}

作 者:haifeiWu

原文链接:https://cloud.tencent.com/developer/article/1333332

版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 权限管理的代码实现与配置文件
    • 只读管理员权限的实现及切点选择
      • 只读管理员权限管理代码实现
        • 具有专门功能的管理员权限控制的切点选择
          • 权限管理的切面代码实现
            • 自定义权限非法异常代码
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档