基于Struts2拦截器的权限控制

来源:互联网 发布:淘宝加入全球购难吗 编辑:程序博客网 时间:2024/05/24 22:46

最近闲来无事,自己做了个通过struts2拦截器的权限控制的小例子。主要是通过struts2的核心拦截器机制,不依赖于容器,实现一个可以精确到方法上的细粒度的权限控制。

     该小例子借鉴了网上一些前辈们,还有学界同行们的项目经验,我取其优秀的部分,稍加加工,改造而成,还非常不完善,欢迎大家批评指正。该小例子只供学习交流,无意于商业化中使用,也无意于挑起任何争端。

    下面是一些类的代码,这里可能需要大家对注解比较熟悉,不过不熟悉也不影响,和xml配置文件起的是一样的作用,都是将属性映射成为表的字段。

首先呢,建立一个注解类,名字叫Permission。这个注解类的代码如下

Java代码
package com.zxyg.web.action.privilege;   
  1.   
  2. import java.lang.annotation.ElementType;   
  3. import java.lang.annotation.Retention;   
  4. import java.lang.annotation.RetentionPolicy;   
  5. import java.lang.annotation.Target;   
  6.   
  7. /**  
  8.  * 权限配置 注解类  
  9.  * @author Lan  
  10.  *  
  11.  */  
  12. @Retention(RetentionPolicy.RUNTIME) //注解的存活时间,整个运行时都存活   
  13. @Target(ElementType.METHOD) //此注解表示只能在方法上面有效   
  14. public @interface Permission {   
  15.     /** 模块名 **/  
  16.     String model();   
  17.     /** 权限值 **/  
  18.     String privilegeValue();   
  19. }  


这个类,就是将来要在方法上打标记的。

接下来要建立几个跟权限相关的实体类了。
首先是权限实体类,类的代码如下

Java代码
  1. package com.zxyg.bean.privilege;   
  2.   
  3. import javax.persistence.Column;   
  4. import javax.persistence.EmbeddedId;   
  5. import javax.persistence.Entity;   
  6. import javax.persistence.Table;   
  7.   
  8. /**  
  9.  * 系统权限实体  
  10.  * @author Lan  
  11.  *   
  12.  */  
  13. @Entity  
  14. @Table(name="t_systemprivilege")   
  15. public class SystemPrivilege {   
  16.     /** 权限值**/  
  17.     private SystemPrivilegePK id;   
  18.     /** 权限名称**/  
  19.     private String name;   
  20.        
  21.     public SystemPrivilege() {}   
  22.   
  23.     public SystemPrivilege(SystemPrivilegePK id) {   
  24.         this.id = id;   
  25.     }   
  26.   
  27.     public SystemPrivilege(String model, String privilegeValue, String name) {   
  28.         this.id = new SystemPrivilegePK(model, privilegeValue);   
  29.         this.name = name;   
  30.     }   
  31.   
  32.     @EmbeddedId //复合主键的标注   
  33.     public SystemPrivilegePK getId() {   
  34.         return id;   
  35.     }   
  36.   
  37.     public void setId(SystemPrivilegePK id) {   
  38.         this.id = id;   
  39.     }   
  40.   
  41.     @Column(length=20, nullable=false)   
  42.     public String getName() {   
  43.         return name;   
  44.     }   
  45.   
  46.     public void setName(String name) {   
  47.         this.name = name;   
  48.     }   
  49. }  


这个类主要包含两个属性,一个是权限值,另外一个是权限的名称,权限值呢,实际也是一个类,这里采用的是复合主键的形式,权限值的实体类代码如下

Java代码
  1. package com.zxyg.bean.privilege;   
  2.   
  3. import javax.persistence.Column;   
  4. import javax.persistence.Embeddable;   
  5.   
  6. /**  
  7.  * 系统权限复合主键类  
  8.  * @author Lan  
  9.  *   
  10.  */  
  11. @Embeddable  
  12. public class SystemPrivilegePK {   
  13.     /** 模块名 **/  
  14.     private String model;   
  15.     /** 权限值 **/  
  16.     private String privilegeValue;   
  17.        
  18.     public SystemPrivilegePK() {}   
  19.   
  20.     public SystemPrivilegePK(String model, String privilegeValue) {   
  21.         this.model = model;   
  22.         this.privilegeValue = privilegeValue;   
  23.     }   
  24.   
  25.     @Column(length=25, name="model")   
  26.     public String getModel() {   
  27.         return model;   
  28.     }   
  29.   
  30.     public void setModel(String model) {   
  31.         this.model = model;   
  32.     }   
  33.   
  34.     @Column(length=20, name="privilegeValue")   
  35.     public String getPrivilegeValue() {   
  36.         return privilegeValue;   
  37.     }   
  38.   
  39.     public void setPrivilegeValue(String privilegeValue) {   
  40.         this.privilegeValue = privilegeValue;   
  41.     }   
  42. }  


这个类有两个属性,一个是模块的名称,一个是模块对应的值。其实呢,这里在数据库里面的权限表里存储的就是对某个资源的什么操作,描述名称是什么,比如
role delete 角色删除
意思就是对role这个模块的删除操作,这个呢,就是一个具体的权限。
最后一个实体类就比较简单了,是角色类,类代码如下

Java代码
  1. package com.zxyg.bean.privilege;   
  2.   
  3. import java.util.HashSet;   
  4. import java.util.Set;   
  5.   
  6. import javax.persistence.CascadeType;   
  7. import javax.persistence.Column;   
  8. import javax.persistence.Entity;   
  9. import javax.persistence.FetchType;   
  10. import javax.persistence.GeneratedValue;   
  11. import javax.persistence.Id;   
  12. import javax.persistence.JoinColumn;   
  13. import javax.persistence.JoinTable;   
  14. import javax.persistence.ManyToMany;   
  15. import javax.persistence.Table;   
  16.   
  17. import com.zxyg.bean.organization.Employee;   
  18.   
  19.   
  20. /**  
  21.  * 角色实体  
  22.  * @author Lan  
  23.  *   
  24.  */  
  25. @Entity  
  26. @Table(name="t_role")   
  27. public class Role {   
  28.     /** 主键ID* */  
  29.     private Integer id;   
  30.     /** 角色名称* */  
  31.     private String name;   
  32.     /** 存放权限的集合,角色和权限是多对多的关系 * */  
  33.     private Set<SystemPrivilege> privileges = new HashSet<SystemPrivilege>();   
  34.        
  35.     public Role() {}   
  36.        
  37.     public Role(Integer id) {   
  38.         this.id = id;   
  39.     }   
  40.   
  41.     @Id @GeneratedValue  
  42.     public Integer getId() {   
  43.         return id;   
  44.     }   
  45.   
  46.     public void setId(Integer id) {   
  47.         this.id = id;   
  48.     }   
  49.   
  50.     @Column(length=20, nullable=false)   
  51.     public String getName() {   
  52.         return name;   
  53.     }   
  54.   
  55.     public void setName(String name) {   
  56.         this.name = name;   
  57.     }   
  58.   
  59.     @ManyToMany(cascade=CascadeType.REFRESH, fetch=FetchType.EAGER)   
  60.     @JoinTable(name="t_role_privilege", joinColumns=@JoinColumn(name="roleid"),   
  61.             inverseJoinColumns={@JoinColumn(name="model", referencedColumnName="model"),   
  62.                                 @JoinColumn(name="privilegeValue", referencedColumnName="privilegeValue")}) //中间表,来存放角色、权限的关系   
  63.     public Set<SystemPrivilege> getPrivileges() {   
  64.         return privileges;   
  65.     }   
  66.   
  67.     public void setPrivileges(Set<SystemPrivilege> privileges) {   
  68.         this.privileges = privileges;   
  69.     }   
  70.        
  71.     //定义此方法,方便添加权限   
  72.     public void addPrivilege(SystemPrivilege privilege) {   
  73.         this.privileges.add(privilege);   
  74.     }   
  75. }  


这个类就比较简单了,具体看一下其中的关系即可,这里就不多做赘述了。
当你有一个Action类的时候,需要在方法上加标注描述了。举例如下

Java代码
  1. package com.zxyg.web.action.privilege;   
  2.   
  3. import java.io.Serializable;   
  4.   
  5. import javax.annotation.Resource;   
  6.   
  7. import org.springframework.context.annotation.Scope;   
  8. import org.springframework.stereotype.Controller;   
  9.   
  10.   
  11. import com.opensymphony.xwork2.ActionContext;   
  12. import com.zxyg.bean.privilege.Role;   
  13. import com.zxyg.bean.privilege.SystemPrivilege;   
  14. import com.zxyg.bean.privilege.SystemPrivilegePK;   
  15. import com.zxyg.service.privilege.RoleService;   
  16. import com.zxyg.service.privilege.SystemPrivilegeService;   
  17. import com.zxyg.utils.SiteUrl;   
  18. import com.zxyg.web.action.base.BaseSupport;   
  19.   
  20. @Controller @Scope("prototype")   
  21. public class RoleManageAction extends BaseSupport {   
  22.     private static final long serialVersionUID = 1L;   
  23.     @Resource private RoleService roleService;   
  24.     @Resource private SystemPrivilegeService privilegeService;   
  25.     private Role role;   
  26.        
  27.     //接收前端传过来的权限数组,如"角色添加"、"角色删除"等   
  28.     private SystemPrivilegePK[] privileges;   
  29.        
  30.     //接收前端传过来的roleid参数   
  31.     private Integer roleid;   
  32.        
  33.     public Integer getRoleid() {   
  34.         return roleid;   
  35.     }   
  36.   
  37.     public void setRoleid(Integer roleid) {   
  38.         this.roleid = roleid;   
  39.     }   
  40.   
  41.     public SystemPrivilegePK[] getPrivileges() {   
  42.         return privileges;   
  43.     }   
  44.   
  45.     public void setPrivileges(SystemPrivilegePK[] privileges) {   
  46.         this.privileges = privileges;   
  47.     }   
  48.   
  49.     public Role getRole() {   
  50.         return role;   
  51.     }   
  52.   
  53.     public void setRole(Role role) {   
  54.         this.role = role;   
  55.     }   
  56.   
  57.   
  58.     /**  
  59.      * 显示角色添加页面  
  60.      * @return  
  61.      */  
  62.     @Permission(model="role", privilegeValue="insert")   
  63.     public String addUI() {   
  64.         ActionContext.getContext().put("privileges", privilegeService.getScrollData().getResultlist());   
  65.         return "add";   
  66.     }   
  67.        
  68.     /**  
  69.      * 添加角色  
  70.      * @return  
  71.      */  
  72.     @Permission(model="role", privilegeValue="insert")   
  73.     public String add() {   
  74.         for(SystemPrivilegePK id : privileges) {   
  75.             role.addPrivilege(new SystemPrivilege(id));   
  76.         }   
  77.         roleService.save(role);   
  78.         ActionContext context = ActionContext.getContext();   
  79.         context.put("message""添加角色成功");   
  80.         context.put("urladdress", SiteUrl.readUrl("control.role.list"));   
  81.         return "message";   
  82.     }   
  83.        
  84.     /**  
  85.      * 显示角色修改页面  
  86.      * @return  
  87.      */  
  88.     @Permission(model="role", privilegeValue="update")   
  89.     public String updateUI() {   
  90.         role = roleService.find((Serializable)roleid);   
  91.         ActionContext context = ActionContext.getContext();   
  92.         context.put("role", role);   
  93.         context.put("privileges", privilegeService.getScrollData().getResultlist());   
  94.         context.put("selectprivileges", role.getPrivileges());   
  95.         return "edit";   
  96.     }   
  97.        
  98.     /**  
  99.      * 修改角色  
  100.      * @return  
  101.      */  
  102.     @Permission(model="role", privilegeValue="update")   
  103.     public String update() {   
  104.         Role old_role = roleService.find((Serializable)roleid);   
  105.         old_role.setName(role.getName());   
  106.         old_role.getPrivileges().clear();   
  107.         for(SystemPrivilegePK id : privileges) {   
  108.             old_role.addPrivilege(new SystemPrivilege(id));   
  109.         }   
  110.         roleService.update(old_role);   
  111.         ActionContext context = ActionContext.getContext();   
  112.         context.put("message""修改角色成功");   
  113.         context.put("urladdress", SiteUrl.readUrl("control.role.list"));   
  114.         return "message";   
  115.     }   
  116.        
  117.     /**  
  118.      * 删除角色  
  119.      * @return  
  120.      */  
  121.     @Permission(model="role", privilegeValue="delete")   
  122.     public String delete() {   
  123.         roleService.delete((Serializable)roleid);   
  124.         ActionContext context = ActionContext.getContext();   
  125.         context.put("message""删除角色成功");   
  126.         context.put("urladdress", SiteUrl.readUrl("control.role.list"));   
  127.         return "message";   
  128.     }   
  129. }  


看到这些方法上面的描述了吧,其实最终是要取得这些标注描述再来判断权限的。呵呵,接下来我们就写个拦截器了,这里面就是具体描述,当用户登录后如何和这些方法上的标注相互比对进行权限控制的,拦截器代码如下:

Java代码
  1. package com.zxyg.web.action.privilege;   
  2.   
  3. import java.lang.reflect.Method;   
  4.   
  5. import org.apache.struts2.ServletActionContext;   
  6.   
  7. import com.opensymphony.xwork2.ActionContext;   
  8. import com.opensymphony.xwork2.ActionInvocation;   
  9. import com.opensymphony.xwork2.interceptor.Interceptor;   
  10. import com.zxyg.bean.organization.Employee;   
  11. import com.zxyg.bean.privilege.Role;   
  12. import com.zxyg.bean.privilege.SystemPrivilege;   
  13. import com.zxyg.bean.privilege.SystemPrivilegePK;   
  14. import com.zxyg.utils.SiteUrl;   
  15.   
  16. /**  
  17.  * 使用拦截器进行系统权限的拦截  
  18.  * @author Lan  
  19.  *   
  20.  */  
  21. public class PermissionInterceptor implements Interceptor {   
  22.     private static final long serialVersionUID = 1L;   
  23.   
  24.     public void destroy() {}   
  25.   
  26.     public void init() {}   
  27.   
  28.     /**  
  29.      * 处理权限拦截  
  30.      */  
  31.     public String intercept(ActionInvocation invocation) throws Exception {   
  32.         Employee employee = (Employee) ServletActionContext.getRequest().getSession().getAttribute("employee"); //取得当前登录的用户   
  33.         if (validate(employee, invocation)) {   
  34.             return invocation.invoke();   
  35.         }   
  36.         ActionContext context = ActionContext.getContext();   
  37.         context.put("message""你没有权限执行该操作");   
  38.         context.put("urladdress", SiteUrl.readUrl("control.center.right"));   
  39.         return "message";   
  40.     }   
  41.   
  42.     /**  
  43.      * 校验控制在方法上的拦截  
  44.      */  
  45.     public boolean validate(Employee employee, ActionInvocation invocation) {   
  46.         String methodName= "execute"//定义默认的访问方法   
  47.         Method currentMethod = null;   
  48.         methodName = invocation.getProxy().getMethod(); //通过actionProxy,得到当前正在执行的方法名   
  49.         try {   
  50.             currentMethod = invocation.getProxy().getAction().getClass().getMethod(methodName, new Class[] {}); //利用反射,通过方法名称得到具体的方法   
  51.             /*Method[] methods = invocation.getProxy().getAction().getClass().getMethods(); //如果不确定方法的具体参数,也可以迭代比较,速度较慢  
  52.             for(Method method : methods ) {  
  53.                 if(method.getName().equals(methodName)) {  
  54.                     currentMethod = method;  
  55.                     break;  
  56.                 }  
  57.             }*/  
  58.         } catch (Exception e) {   
  59.         }   
  60.         if (currentMethod != null && currentMethod.isAnnotationPresent(Permission.class)) {   
  61.             Permission permission = currentMethod.getAnnotation(Permission.class); //得到方法上的Permission注解   
  62.             SystemPrivilege privilege = new SystemPrivilege(new SystemPrivilegePK(permission.model(), permission.privilegeValue())); //通过Permission注解构造出系统权限   
  63.             for (Role role : employee.getRoles()) { //迭代用户所具有的具体权限,如果包含,返回true   
  64.                 if (role.getPrivileges().contains(privilege))    
  65.                     return true;   
  66.             }   
  67.             return false;   
  68.         }   
  69.         return true;   
  70.     }   
  71.   
  72. }  


这些代码呢,其实已经简单的描述了下,就是将用户存储在数据库中间表中的角色对应的权限取出来,在构造出用户想访问的action中方法上的权限描述,相互比对,如果包含,则可以访问,否则没有权限访问。

最后就是struts.xml文件的配置了,配置好拦截器,就都搞定了,配置文件如下

Java代码
  1. <?xml version="1.0" encoding="UTF-8" ?>   
  2. <!DOCTYPE struts PUBLIC   
  3.     "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"  
  4.     "http://struts.apache.org/dtds/struts-2.0.dtd">   
  5.   
  6. <struts>   
  7.     <package name="privilege" namespace="/control/role" extends="struts-default">   
  8.         <interceptors>   
  9.             <!-- 定义权限拦截器 -->   
  10.             <interceptor name="permission" class="com.zxyg.web.action.privilege.PermissionInterceptor"/>   
  11.             <!-- 定义拦截器栈,所谓拦截器栈,是指由一个或多个拦截器组成 -->   
  12.             <interceptor-stack name="permissionStack">   
  13.                 <!-- struts2提供的拦截器栈,包含了struts2的很多核心拦截器 -->   
  14.                 <interceptor-ref name="defaultStack" />   
  15.                 <!-- 自己定义的放在最后面,struts2定义的放在前面 -->   
  16.                 <interceptor-ref name="permission" />   
  17.             </interceptor-stack>   
  18.         </interceptors>   
  19.            
  20.         <!-- 为此包下的所有action应用拦截器 -->   
  21.         <default-interceptor-ref name="permissionStack" />   
  22.            
  23.         <global-results>   
  24.             <result name="message">/WEB-INF/page/share/message.jsp</result>   
  25.         </global-results>   
  26.            
  27.         <!-- 显示角色列表 -->   
  28.         <action name="list" class="roleListAction" method="execute">   
  29.             <result name="success">/WEB-INF/page/privilege/rolelist.jsp</result>   
  30.         </action>   
  31.            
  32.         <!-- 角色管理 -->   
  33.         <action name="manage_*" class="roleManageAction" method="{1}">   
  34.             <result name="add">/WEB-INF/page/privilege/addrole.jsp</result>   
  35.             <result name="edit">/WEB-INF/page/privilege/editrole.jsp</result>   
  36.         </action>   
  37.     </package>   
  38. </struts>  


ok,到这里的时候,所有工作就完成了,当用户登录后,就可以进行访问进行权限拦截了的试验了。

原创粉丝点击