`
xxp3369
  • 浏览: 151193 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

权限管理模块分析

阅读更多
巴巴运动网的后台权限管理模块主要采用了两大核心技术:java的反射和自定义注解
即是权限管理,让人很容易就想到过滤,也许也可以叫做权限过滤吧,即然是过滤,那就
总得有个过滤的粒度吧,根据不同的需求控制的粒度都是不同的,粗粒度的过滤
用我们最常用的过滤器对request对象里的请求url地址进行过滤即可,细粒度的过滤
甚至可以考虑将需要的每个方法里写死权限验证,当然适合需求即好.巴巴运动网采用
了用黎老师的话所说的最优雅,粗细粒度可控制,无侵入性.下面对此进行详细的介绍.
   首先这里简单的介绍下整个权限管理模块的实体类的相关设计:
权限实体设计如下:
---------------------------------------------------------------------------------------------------------------------
/**
这里权限的id我们采用了联合主键,这样从面象对象的角度,它具有更直观,更合理的设计,联合主键类里有model(代表模块的名称),privilegeValue(操纵该模块所需要的权限值)
**/
private SystemPrivilegePK id;
private String name;   //权限名称
---------------------------------------------------------------------------------------------------------------------
整个权限管理模块的设计似乎并没有考虑为每个用户单独分配权限,而是采用了权限组的
模式,先将一系列的权限添加到一个权限组,然后将相应的权限组分给相就的用户即可.
权限组的实体设计如下:
----------------------------------------------------------------------------------------------------------------------
         private Integer id;         //权限组的ID
         private String name;       //权限组的名称
   存放该组所拥有的权限的set集合.
  它与权限表是多对多的关系,即一个组里可以有多个权限,一个权限可以存在于
   不同的组里.这里给出具体的多对多注解
该注解告诉jpa该集合用于多对多关系的映射,级联系关系为更新,强制不使用懒加载
        @ManyToMany(cascade=CascadeType.REFRESH, fetch=FetchType.EAGER)
    //该注解告诉jpa会生成一个中间表,表名为group_privilege,这里的joinColumns表示
    生成的数据库表里将有名为group_id的字段,将且该字段为外键参考于该实体类,即该实体类所映射的数据库表的主键id,
        @JoinTable(name="group_privilege",joinColumns=@JoinColumn(name="group_id"),
//inverseJoinColumns表时反向关联到该数据库表的字段,这里的反向指的就是对应的
SystemPrivilege实体类了,这里的两个joinColumn分别表示 生成的数据库表里将有名为
model的字段,其作为外键参考于SystemPrivilege实体类的主键id(默认外键参考于该实体类的id ,     但 由于该id采用了联合主键,所以要具体指定参考了哪个字段)的model字段,名为privilegeValue的字段,其作为外键参考于SystemPrivilege实体类的privilegeValue字段.
          inverseJoinColumns={@JoinColumn(name="model",referencedColumnName="model"),
        @JoinColumn(name="privilegeValue",referencedColumnName="privilegeValue")})
         private Set<SystemPrivilege> privileges = new HashSet<SystemPrivilege>();
----------------------------------------------------------------------------------------------------------------------
上面两个实体类即分别表示了权限,和权限组,接下来则是考虑如何设计整个权限模块了,首先当然是考虑的在哪一层加入权限控制,如果是在dao层,那么当用户请求到action,action调用相应的业务方法,业务方法可能涉及到数据库的增删改查,这时业务层里又会去调用dao层的方法来访问数据库,结果在这一层发现这个用户没有相应的权限,最终操纵失败!那么前面做的那么多全是多余的,这样的设计显然是非常不合理的,不难发现,权限的控制在越靠近前端就是越优的,我们把目标选在了action控制层.
   经过上面的分析后,决定将权限的控制放在action这一层来实现,既然采用了spring,很自然就能想到spring的aop了,确实,它非常的复合这种应用模式,那么问题又来了,我们应该以什么样的方式来告诉程序,要有什么样的权限才能调用相应的action的方法呢,不可能为每个action的方法在数据库里有条记录标记上调用该方法要什么什么样的权限,这样的做法非常的不直观,维护性也是很差的,幸好java为我们提供了很多有用的技术,这里我们采用了注解,在相应的方法上注解上调用该方法所必要的权限,这样在有用户试图调用该方法时,aop先拦截到该次方法的调用,判断该方法上是否存在相应的注解,如不存在则该方法是共公的,如存在相应的注解,则通用java为我们提供的反射来取得该注解,并得到注解上的值来进行更多的相应的处理,看起来一切都规划的非常好,天衣无缝,那我们就先从这个自定义注解开始吧.
-------------------------------------------------------------------------------------------------------------------
自定义注解类的设计:
      //该注解表示该注解在程序运行期会被处理
      @Retention(RetentionPolicy.RUNTIME)
      //该注解表示该注解只能标识在方法上
@Target(ElementType.METHOD)
public@interfacePrivilege {
//表示该自定义注解里的元素,该元素表示模块名
        String model();
        //该元素表示操纵该模块名所要的权限值
        String privilegeValue();
}

设计好自定义注解后,接下来要做的就是把需要权限的action的相应的方法都加上相应的自定义注解了。例:这里即表示该方法属于brand(品牌)模块,访问该方法需要view权限值
    @Override@Privilege(model="brand", privilegeValue="view")
    public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
}
做好这一些就可以开始配置spring的AOP了.最终会发现spring的aop是拦截不到dispatchAction里的所有方法的,经过黎老师的仔细研究才发现原来ActionServlet对dispatchAction里的方法调用采用了java里的反射,spring的AOP拦截不到,它只能拦截到基于action的execute方法.于是最终放弃了spring的AOP(这里也告诉了我们,处事要灵活,没必要死扣).spring的AOP是在目标方法被调用之前进行拦截,拦截之后可以在目标方法调用之前和之后做自己想做的处理,基于这个思想,我们只要找出是谁调用的我们写在action和dispatchAction里的方法的那个控制器即可。由于整个项目采用了struts+spring+jpa+hibernate,并用spring的控制器替换了struts自己的控制器来完成struts和spring的整合,所以我们要找的那个控制器应该是spring的DelegatingRequestProcessor类,黎老凭多年的工作经验很肯定的就告诉了我们,DelegatingRequestProcessor类里的processActionPerform方法就是用来负责调用action和dispatchAction里的相应的方法的,我们只须要自己写个类,继承DelegatingRequestProcessor,并复盖processActionPerform,重点是要在struts-config.xml配置文件里把控制器换成我们现在这个自己写的类.由于在该方法里提供给了我们HttpServletRequest request,
           HttpServletResponse response, Action action, ActionForm form,
           ActionMapping mapping五个形参对象,那么我们可以先判断这里的action对象它是继承自Action还是dispatchAction,如果它是继承自Action,则根据Action类的特性,它只存在唯一的动作(方法),即execute,如果它继承自DispatchAction,那么根据访问dispatchActon的特性,用户的访问路径里一定带有要访问的具体的方法名,所以我们可以根据request.getParameter(mapping.getParameter());从request域里拿到用户试图调用的方法名,确定了用户将试图调用的方法名后,接下来的事就变的简单了,我们首先尝试通过方法名,和固定的形参通过该action返回用户试图调用的具体方法;
//注意这里使用的方法是Action.getClass().getDeclaredMethod()
//它可以获取包括private在内的方法.
method = Action.getClass().getDeclaredMethod(methodname,ActionMapping.class, ActionForm.class,HttpServletRequest.class,HttpServletResponse.class);
顺利得到该方法后,我们就可以通用method.isAnnotationPresent(Privilege.class)来判断该方法上是否存在我们预先定义好的注解,如果不存在,则该action或dispatchAction里的方法为共公的,我们这时候则可以直接调用DelegatingRequestProcessor类的super().processActionPerform方法,让程序正确的执行,如果存在我们预先定义的注解,我们首先返回该方法上的注解,然后得到该注解上我们定义的model和privilegeValue的具体值,然后我们通过这两个值可以构造出一个SystemPrivilegePK对象,忘了介绍,该对象即为权限的联合主键id类.到了这一步整个权限模块几乎完工了,如果用户正确登录该系统,我们会将用户的信息存入session内,在这里我们都构造出了SystemPrivilegePK对象,接下来只需从session拿到当前访问该方法的用户,并且返回该用户所在的权限组,然后遍历整个权限组,一一判断权限组里是否有权限的id(即联合主键)与我们通过注解构造出来的id相equals的(这里特别要注意, SystemPrivilegePK,是要重写hashCode()和equals方法的,具体实现见源码),如果存在equals,则说明该用户是有权限访问的,则调用DelegatingRequestProcessor类的super().processActionPerform方法让程序正确执行,如果不存在该权限id,说明该用户并没有权限访问,则程序直接跳转到相应的提示页面.致此整个权限大致流程介绍完了,写的非常乱,希望对整个巴巴运动网权限这一块不太明白的同学有一点点帮助吧,自己能力也有限,如果有时间,会在完善一下分析






在这给出我今天上午写好的关于注解权限过滤的代码,性能很差的,只是实现了功能:
PrivilegeDelegatingProcessor.java:
------------------------------------------------
package com.iwtxokhtd.news.bean;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.struts.DelegatingRequestProcessor;

import com.iwtxokhtd.news.bean.employee.Employee;
import com.iwtxokhtd.news.bean.privilege.PrivilegeGroup;
import com.iwtxokhtd.news.bean.privilege.SystemPrivilege;
import com.iwtxokhtd.news.bean.privilege.SystemPrivilegePK;
import com.iwtxokhtd.news.service.employee.EmployeeDAO;
import com.iwtxokhtd.news.utils.SiteUrl;
import com.iwtxokhtd.news.web.action.privilege.Privilege;

public class PrivilegeDelegatingRequestProcessor extends
  DelegatingRequestProcessor {
private static ApplicationContext ctx;
private static EmployeeDAO employeeDao;

public PrivilegeDelegatingRequestProcessor(){
  ctx=new ClassPathXmlApplicationContext("beans.xml");
  employeeDao=(EmployeeDAO)ctx.getBean("employeeDAOBean");
}
@Override
protected ActionForward processActionPerform(HttpServletRequest request, HttpServletResponse response, Action action, ActionForm form, ActionMapping mapping) throws IOException, ServletException {
     String methodname="";
     if(mapping.getParameter()==null||"".equals(mapping.getParameter())){
       methodname="execute";
     }else{
       methodname=request.getParameter(mapping.getParameter());
     }
            Method method=null;
            try {
             method=action.getClass().getDeclaredMethod(methodname, ActionMapping.class,ActionForm.class,HttpServletRequest.class,HttpServletResponse.class);
       Boolean flag=method.isAnnotationPresent(Privilege.class);
       Privilege priv=method.getAnnotation(Privilege.class);
       //如果不存在注解,则是公共的方法,可以执行下去
       if(!flag){
        return super.processActionPerform(request, response, action, form, mapping);
       }else{
        //就是设置了权限的方法
        //取得注解中的值
        String model=priv.model();
        String privilegeValue=priv.privilegeValue();
                    //构造权限主键
                    SystemPrivilegePK privilegepk=new SystemPrivilegePK(model,privilegeValue);
                    //取得登录的用户名
                    String username=(String) request.getSession().getAttribute("username");
                    //根据用户名取得员工实体对象
                      Employee employee=null;
                      if(username!=null&&!"".equals(username)){
                       employee=employeeDao.find(Employee.class, username);
                      }
                      SystemPrivilegePK dbpk=null;
                      Set<SystemPrivilegePK> privset=new HashSet<SystemPrivilegePK>();
                    //打印该员工的权限
                    for(PrivilegeGroup group:employee.getPrivilegegroups()){
      for(SystemPrivilege syspriv:group.getPrivileges()){
                       //根据数据库中的权限模块和权限值构造权限主键
                              dbpk=new SystemPrivilegePK(syspriv.getPkid().getModel(),syspriv.getPkid().getPrivilegeValue());
                              if(!privset.contains(dbpk)){
                               privset.add(dbpk);
                              }
                       }
                    }
                    if(privset.contains(privilegepk)){
                     return super.processActionPerform(request, response, action, form, mapping);
                    }else{
                  request.setAttribute("message", "你没有此权限,请与管理员联系!");
            request.setAttribute("urladdress", SiteUrl.readUrl("employee.has.no.privileges"));
         return mapping.findForward("noprivilege");
                    }
       }
   }catch(NoSuchMethodException e){
    e.printStackTrace();
   }
   return super.processActionPerform(request, response, action, form, mapping);
}
}

分享到:
评论
1 楼 kljismi 2011-03-10  
你好,我现在正在开这项目的代码,但是我不明白
@Privilege(model="brand", privilegeValue="view")   brand和view这两个值是从那得来的,需要配置吗,还是存在数据库中哦,

相关推荐

    10_传智播客巴巴运动网_权限管理模块分析

    "10_传智播客巴巴运动网_权限管理模块分析"这一主题聚焦于如何设计和实现一个有效的权限管理系统。这个主题可能涵盖以下几个关键知识点: 1. **权限模型**:权限模型是权限管理的基础,通常包括角色(Role)、资源...

    毕业设计论文-教育报表管理系统权限管理模块的实现.zip

    在教育领域,报表管理系统是至关重要的工具,它能够帮助管理者分析和决策,而权限管理模块则是确保数据安全和操作合规性的核心部分。本文将围绕这一主题,详细介绍权限管理模块的设计与实现。 权限管理是系统安全的...

    通用权限模块设计与分析

    总的来说,这些文档组合起来提供了关于权限模块设计的全方位视角,从理论模型到实际应用,从系统设计到具体实现,涵盖了权限管理的各个方面。在设计此类模块时,开发者需要考虑系统的可扩展性、灵活性和安全性,以...

    权限管理模块源码 及数据库设计

    本文将深入探讨一个权限管理模块的源码及其数据库设计,非常适合初学者学习和理解。 首先,权限管理的核心目标是实现用户、角色和资源之间的关系管理。在系统中,用户通过扮演不同的角色来获取对特定资源(如文件、...

    分析图书管理系统的用户管理模块且绘制类图 (1).docx

    本文将详细介绍用户管理模块的设计和实现,包括用户管理模块的主要功能、类图设计、实验步骤和结果分析等。 一、用户管理模块的主要功能 用户管理模块的主要功能包括: 1. 用户注册:用户可以注册账户并登录系统...

    GIS用户权限管理-基于角色的用户权限管理模块

    总的来说,"GIS用户权限管理-基于角色的用户权限管理模块"是一个全面且灵活的解决方案,它覆盖了从数据库支持、角色管理、用户权限分配到地图访问控制的各个环节,并且具备二次开发能力,适应不同场景下的GIS应用...

    毕业答辩-ASP.NET教育报表管理系统-权限管理模块(源代码论文).rar

    【标题】:“毕业答辩-ASP.NET教育报表管理系统-权限管理模块(源代码论文).rar”这一压缩包文件,主要包含了使用ASP.NET技术开发的一个教育报表管理系统的权限管理模块的源代码和相关论文。该系统旨在为教育机构提供...

    统一用户及权限管理系统需求分析

    - **重用性**:系统作为一个组件,可以被不同的管理系统重用,避免了每次开发新系统时都要重新设计权限管理模块。 - **权限类型**:系统支持两种主要的权限管理方式:功能权限管理和资源权限管理。功能权限可以在...

    某实际项目的权限管理模块(很全~!java源码!+说明文档~+学习文档)

    这个实际项目的权限管理模块提供了全面的功能和详尽的文档,对于开发者来说,是一个宝贵的资源,特别是对于那些想要深入理解权限控制概念、Java编程以及如何将这些概念应用到实际项目中的初学者。 权限管理通常涉及...

    进销存管理系统权限管理模块的设计.pdf

    权限管理模块是系统中的关键组成部分,确保不同用户按照其职责和权限访问相应的信息。本文主要探讨了进销存管理系统的设计,特别是权限管理模块的设计,以提升系统的安全性和效率。 在系统需求分析阶段,作者首先对...

    javaweb权限管理模块.rar

    JavaWeb权限管理模块是Web应用程序中至关重要的组成部分,它确保了不同用户访问资源的安全性和可控性。这个RAR压缩包可能包含了一个完整的权限管理系统的核心组件,包括数据库脚本、示例代码以及相关的说明图表。 ...

    完整版用户管理模块 1.3.rar

    1.3版本可能会增加新的权限设置,例如基于资源的权限控制(RBAC),使得权限管理更为灵活和精确。 用户行为跟踪和审计日志也是重要的安全措施。通过记录用户的登录、登出、修改资料等行为,可以追踪异常活动,及时...

    ASP.NET教育报表管理系统-权限管理模块(源代码+论文)

    ASP.NET教育报表管理系统是一款专为K12教育领域设计的软件,其权限管理模块是系统核心功能之一。本文将深入探讨该系统的权限管理模块及其在ASP.NET技术框架下的实现细节。 首先,ASP.NET是由微软公司开发的一个开源...

    ASP.NET教育报表管理系统-权限管理模块(源代码+论文).rar

    ASP.NET教育报表管理系统是一款专为教育领域设计的报表管理平台,其权限管理模块是系统核心功能之一,确保了用户在访问、操作数据时的安全性和隐私性。本项目以ASP.NET技术为基础,结合C#编程语言,构建了一个高效、...

    进销存管理系统-权限管理模块.doc

    通过以上分析,我们可以看出,进销存管理系统中的权限管理模块是一个关键的组成部分,它不仅涉及到用户的角色划分,还涉及到界面设计和事件处理,是系统安全性和用户体验的重要保证。在实际开发中,还需要结合数据库...

    PHP权限管理系统源代码

    在这个权限管理系统中,Model负责数据的处理,View负责展示,而Controller处理用户请求并协调Model和View。 4. **数据库交互**:PHP常使用MySQL或其他SQL数据库来存储用户信息、角色和权限。源代码中应包含使用PHP...

    分析图书管理系统的用户管理模块,且绘制类图分享.pdf

    "图书管理系统用户管理模块分析与类图设计" 本文将对图书管理系统的用户管理模块进行分析,并设计类图。用户管理模块是图书管理系统的核心组件之一,负责管理用户、管理用户密码、管理用户权限和浏览用户信息。我们...

    66.基于ASP.NET的教育报表系统-权限管理模块构建与设计实现(源代码完整+学术LW).zip

    资源包内提供了完整的源代码,展示了权限管理模块从需求分析、设计到实现的全过程。这些代码不仅展示了如何创建用户角色、分配权限、验证访问权限等核心功能,还融入了最佳实践,提高了系统的健壮性和可维护性。 ...

    学生管理系统登录模块

    系统管理员可以拥有完全的权限管理系统,而用户只拥有查询信息和查询信息的权限。本系统包括学生信息注册管理、查询信息管理、学生信息删除信息管理、学生登入管理模块。 知识点1:系统设计目的 本系统的设计目的...

Global site tag (gtag.js) - Google Analytics