SpringMVC+Annotation实现方法、按钮级别的细粒度权限控制


常用的权限系统设计模式是以角色为核心的,即角色是具有相同权限的一类人员的集合:

1.     一个角色可以有包含多个操作人员,一个操作人员也可以属于多个角色

2.     一个角色可以具有多个功能的操作权限,一个功能也可以被多个角色所拥有。

在登录时通过查询登录用户所属角色,即可得到个用户的所有功能集合,如下图:



多数业务系统的页 面功能菜单设计是以三级为标准的,即一级功能菜单、二级功能菜单、三级功能菜单,通常情况下一二级功能菜单只是用于功能分类,是不具有功能访问地址的,三 级菜单才是功能的真正入口,常规权限系统就是通过控制每个人员对应的功能菜单的显示与隐藏来实现权限控制。要实现细粒度权限控制,可在设计功能表时再加入 第四层:页面元素,隶属于第三层功能菜单,这些页面元素用来标识功能页面中的每一个功能按钮,如增加、修改、删除、查询都可算是页面元素,在为角色分配权 限时,第四层也同样纳入统一权限管理,如果有此页面元素的权限,则页面上就显示该按钮,如果没有此页面元素的功能权限,则该按钮就不会显示出来。


对于没有权限访问的功能或页面除了进行前台的隐藏之外,还需要在后台访问时进行权限的验证,否则操作人员绕开页面直接通过输入URL访问功能就会造成权限漏洞,通过SpringMVC+Annotation的方式可以轻松实现,代码如下:

第一步:创建SpringMVC拦截器,拦截所有需要进行权限验证的功能请求

     <!-- 开启注解 -->
    <mvc:annotation-driven/>
    <!-- 静态资源访问 -->
     <mvc:resources location="/static/" mapping="/static/**"/> 
      
     <!-- 拦截器 -->
      <mvc:interceptors>  
        <!-- 多个拦截器,顺序执行 -->  
        <mvc:interceptor>  
          <!-- 如果不配置或/**,将拦截所有的Controller -->
           <mvc:mapping path="/**" /> 
           <!-- 在Freemarker界面展示之前做一些通用处理   -->
           <bean class="xx.xxxx.core.web.FreeMarkerViewInterceptor"></bean>  
        </mvc:interceptor>  
    </mvc:interceptors>  

第二步:创建作用于Method级别的Annotation类,用于传入功能ID

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Permission {

    /**
     * 功能ID,该功能ID,对应数据库中的功能ID
     * @return
     * @version V1.0.0
     * @date Jan 13, 2014 4:59:35 PM
     */
    String value();
    
}

第三步:通过静态常量建立数据库中的功能ID与执行方法的一对一关系

public class FuncConstants {

    /**
     * 系统管理-角色管理-增加角色
     */
    public final static String Xtgl_Jsgl_AddJs = "4399d98bb0d84114acb5693081e83bc9";
    /**
     * 系统管理 - 部门管理- 部门列表
     */
    public final static String Xtgl_Bmgl_BmList = "dbc4bf80f8b6418788b79de204d37932";
    
}

第四步:在SpringMVC拦截器中验证权限

/**
 * FreeMarker视图拦截器,页面展示之前做一些通用处理
 * @version V1.0.0
 * @date Dec 12, 2013 4:20:04 PM
 */
public class FreeMarkerViewInterceptor extends HandlerInterceptorAdapter {

    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
        
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object arg2, ModelAndView view) throws Exception {
        String contextPath = request.getContextPath();
        if (view != null) {
            request.setAttribute("base", contextPath);
        }
    }
  
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        
        //处理Permission Annotation,实现方法级权限控制
        HandlerMethod method = (HandlerMethod)handler;
        Permission permission = method.getMethodAnnotation(Permission.class);
        
        //如果为空在表示该方法不需要进行权限验证
        if (permission == null) {
            return true;
        }
        
        //验证是否具有权限
        if (!WebUtil.hasPower(request, permission.value())) {
            response.sendRedirect(request.getContextPath()+"/business/nopermission.html");
            return false;
        }
        return true;
        
        
        //注意此处必须返回true,否则请求将停止
        //return true;
    }

}

至此,基于按钮、方法验证的细粒度权限体系完成!

posted @ 2015-04-10 15:46  夜的柒章  阅读(5452)  评论(0编辑  收藏  举报