自定义注解+拦截器实现权限控制

30 篇文章 0 订阅
11 篇文章 0 订阅

今天刚学习了通过自定义注解+拦截器实现权限控制,自己花了点时间整理,发到网站同网友交流分享。

一、定义一个自定义注解类

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import java.lang.annotation.Retention;  
  2. import java.lang.annotation.RetentionPolicy;  
  3.   
  4. /** 
  5.  * 自定义注解 
  6.  * @author grace 
  7.  * 
  8.  */  
  9. @Retention(RetentionPolicy.RUNTIME)  
  10. public @interface Limit{  
  11.      String module();  //模块名称  
  12.      String privilege(); //操作名称  
  13. }  

二、建好所需要的表

[sql]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #权限组表  
  2. CREATE TABLE `sys_role` (  
  3.   `id` varchar(36),                             #编号  
  4.   `remark` TEXT,                                #备注  
  5.   `nameVARCHAR(100)  DEFAULT NULL,             #名称  
  6.   PRIMARY KEY (`id`)  
  7. )  
[sql]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #操作表  
  2. CREATE TABLE sys_popedom  
  3. (  
  4.    popedomModule       VARCHAR(30),                              #模块名称  
  5.    popedomPrivilege    VARCHAR(30),                              #操作名称  
  6.    sort                INTEGER(11),                              #排序  
  7.    title               VARCHAR(200),                             #提示  
  8.    popedomName         VARCHAR(200),                             #标题  
  9.    remark              TEXT,                                     #说明  
  10.    PRIMARY KEY(popedomModule,popedomPrivilege)  
  11. )  
[sql]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #操作权限表  
  2. CREATE TABLE sys_popedom_privilege  
  3. (  
  4.    roleId         VARCHAR(36),        #权限组编号  
  5.    popedomModule     VARCHAR(30),     #模块名称  
  6.    popedomPrivilege  VARCHAR(30),     #操作名称  
  7.    PRIMARY KEY(roleId,popedomModule,popedomPrivilege)  
  8. )  


解释下以上3个表的作用:

1.权限组表:定义了一个权限,权限有id,name和remark。



2.操作表:该表相当于是你这个项目里所有的权限。popedomModule代表一个大的功能模块,popedomPrivilege代表一个模块下的具体操作:常见的有增删改查,可参考下图理解。



3.操作权限表:该表是权限组所对应的模块和操作。例子:如下图的roleId为8af0897545e4c91b0145e4cd385d0002,在权限组表中对应的是系统管理员权限组(见上上图),该权限组拥有的模块和操作名称在下图第二三列,可对应上图知道功能。说明:系统管理员权限组在当前系统中,只拥有下图所示的模块为city和code的所有操作权限,没有模块为company下的任何操作权限。通过将用户分配到不同的权限组,和设置权限组的拥有的模块和操作,就可以实现权限控制。



三、定义上面三个表所对应的类和*.hbm.xml(如果需要)

权限组表:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /* 
  2.  * SysRole:权限组表 
  3.  */  
  4. @SuppressWarnings("serial")  
  5. public class SysRole implements java.io.Serializable {  
  6.     private String id;  
  7.     private String name;  
  8.     private String remark;  
  9.   
  10.     public String getId() {  
  11.         return id;  
  12.     }  
  13.   
  14.     public void setId(String id) {  
  15.         this.id = id;  
  16.     }  
  17.   
  18.     public String getName() {  
  19.         return name;  
  20.     }  
  21.   
  22.     public void setName(String name) {  
  23.         this.name = name;  
  24.     }  
  25.   
  26.     public String getRemark() {  
  27.         return remark;  
  28.     }  
  29.   
  30.     public void setRemark(String remark) {  
  31.         this.remark = remark;  
  32.     }  
  33.   
  34. }  

注:因为在操作表(sys_popedom)和权限操作表(sys_popedom_privilege)中都为联合主键。因此在这里,我对这两个类都使用:新建一个类用来存放联合主键。

操作表:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /* 
  2.  * 操作表 
  3.  */  
  4. @SuppressWarnings("serial")  
  5. public class SysPopedom  implements java.io.Serializable{  
  6. /* 
  7.  * CREATE TABLE sys_popedom 
  8. ( 
  9.    popedomModule       VARCHAR(30),                              #模块名称 
  10.    popedomPrivilege    VARCHAR(30),                              #操作名称 
  11.    sort                INTEGER(11),                              #排序 
  12.    title               VARCHAR(200),                             #提示 
  13.    popedomName         VARCHAR(200),                             #标题 
  14.    remark              TEXT,                                     #说明 
  15.    PRIMARY KEY(popedomModule,popedomPrivilege) 
  16. ) 
  17.  */  
  18.     private SysPopedomId id;//主键 OID  
  19.     private Integer sort;  
  20.     private String title;  
  21.     private String popedomName;  
  22.     private String remark;  
  23.       
  24.     public SysPopedomId getId() {  
  25.         return id;  
  26.     }  
  27.     public void setId(SysPopedomId id) {  
  28.         this.id = id;  
  29.     }  
  30.     public Integer getSort() {  
  31.         return sort;  
  32.     }  
  33.     public void setSort(Integer sort) {  
  34.         this.sort = sort;  
  35.     }  
  36.     public String getTitle() {  
  37.         return title;  
  38.     }  
  39.     public void setTitle(String title) {  
  40.         this.title = title;  
  41.     }  
  42.     public String getPopedomName() {  
  43.         return popedomName;  
  44.     }  
  45.     public void setPopedomName(String popedomName) {  
  46.         this.popedomName = popedomName;  
  47.     }  
  48.     public String getRemark() {  
  49.         return remark;  
  50.     }  
  51.     public void setRemark(String remark) {  
  52.         this.remark = remark;  
  53.     }  
  54.       
  55. }  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 操作表中的联合主键类 
  3.  * @author grace 
  4.  * 
  5.  */  
  6. @SuppressWarnings("serial")  
  7. public class SysPopedomId implements java.io.Serializable {  
  8.     private String popedomModule;  
  9.     private String popedomPrivilege;  
  10.   
  11.     public String getPopedomModule() {  
  12.         return popedomModule;  
  13.     }  
  14.       
  15.     public void setPopedomModule(String popedomModule) {  
  16.         this.popedomModule = popedomModule;  
  17.     }  
  18.   
  19.     public String getPopedomPrivilege() {  
  20.         return popedomPrivilege;  
  21.     }  
  22.   
  23.     public void setPopedomPrivilege(String popedomPrivilege) {  
  24.         this.popedomPrivilege = popedomPrivilege;  
  25.     }  
  26.   
  27.     @Override  
  28.     public int hashCode() {  
  29.         final int prime = 31;  
  30.         int result = 1;  
  31.         result = prime * result  
  32.                 + ((popedomModule == null) ? 0 : popedomModule.hashCode());  
  33.         result = prime  
  34.                 * result  
  35.                 + ((popedomPrivilege == null) ? 0 : popedomPrivilege.hashCode());  
  36.         return result;  
  37.     }  
  38.   
  39.     @Override  
  40.     public boolean equals(Object obj) {  
  41.         if (this == obj)  
  42.             return true;  
  43.         if (obj == null)  
  44.             return false;  
  45.         if (getClass() != obj.getClass())  
  46.             return false;  
  47.         final SysPopedomId other = (SysPopedomId) obj;  
  48.         if (popedomModule == null) {  
  49.             if (other.popedomModule != null)  
  50.                 return false;  
  51.         } else if (!popedomModule.equals(other.popedomModule))  
  52.             return false;  
  53.         if (popedomPrivilege == null) {  
  54.             if (other.popedomPrivilege != null)  
  55.                 return false;  
  56.         } else if (!popedomPrivilege.equals(other.popedomPrivilege))  
  57.             return false;  
  58.         return true;  
  59.     }  
  60. }  


操作权限表:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 操作权限表 
  3.  * @author grace 
  4.  * 
  5.  */  
  6. @SuppressWarnings("serial")  
  7. public class SysPopedomPrivilege implements java.io.Serializable {  
  8.     /* 
  9.      * CREATE TABLE sys_popedom_privilege  
  10.      * (  
  11.      *   roleId VARCHAR(36), #权限组编号 
  12.      *   popedomModule VARCHAR(30), #模块名称  
  13.      *   popedomPrivilege VARCHAR(30), #操作名称 
  14.      *   PRIMARY KEY(roleId,popedomModule,popedomPrivilege)  
  15.      * ) 
  16.      */  
  17.   
  18.     private SysPopedomPrivilegeId id;  
  19.   
  20.     public SysPopedomPrivilegeId getId() {  
  21.         return id;  
  22.     }  
  23.   
  24.     public void setId(SysPopedomPrivilegeId id) {  
  25.         this.id = id;  
  26.     }  
  27.   
  28. }  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 操作权限表的联合主键类 
  3.  * @author grace 
  4.  * 
  5.  */  
  6. @SuppressWarnings("serial")  
  7. public class SysPopedomPrivilegeId implements java.io.Serializable {  
  8.   
  9.     private String roleId;  
  10.     private String popedomModule;  
  11.     private String popedomPrivilege;  
  12.   
  13.     public String getRoleId() {  
  14.         return roleId;  
  15.     }  
  16.   
  17.     public void setRoleId(String roleId) {  
  18.         this.roleId = roleId;  
  19.     }  
  20.   
  21.     public String getPopedomModule() {  
  22.         return popedomModule;  
  23.     }  
  24.   
  25.     public void setPopedomModule(String popedomModule) {  
  26.         this.popedomModule = popedomModule;  
  27.     }  
  28.   
  29.     public String getPopedomPrivilege() {  
  30.         return popedomPrivilege;  
  31.     }  
  32.   
  33.     public void setPopedomPrivilege(String popedomPrivilege) {  
  34.         this.popedomPrivilege = popedomPrivilege;  
  35.     }  
  36.   
  37.     @Override  
  38.     public int hashCode() {  
  39.         final int prime = 31;  
  40.         int result = 1;  
  41.         result = prime * result  
  42.                 + ((popedomModule == null) ? 0 : popedomModule.hashCode());  
  43.         result = prime  
  44.                 * result  
  45.                 + ((popedomPrivilege == null) ? 0 : popedomPrivilege.hashCode());  
  46.         result = prime * result + ((roleId == null) ? 0 : roleId.hashCode());  
  47.         return result;  
  48.     }  
  49.   
  50.     @Override  
  51.     public boolean equals(Object obj) {  
  52.         if (this == obj)  
  53.             return true;  
  54.         if (obj == null)  
  55.             return false;  
  56.         if (getClass() != obj.getClass())  
  57.             return false;  
  58.         final SysPopedomPrivilegeId other = (SysPopedomPrivilegeId) obj;  
  59.         if (popedomModule == null) {  
  60.             if (other.popedomModule != null)  
  61.                 return false;  
  62.         } else if (!popedomModule.equals(other.popedomModule))  
  63.             return false;  
  64.         if (popedomPrivilege == null) {  
  65.             if (other.popedomPrivilege != null)  
  66.                 return false;  
  67.         } else if (!popedomPrivilege.equals(other.popedomPrivilege))  
  68.             return false;  
  69.         if (roleId == null) {  
  70.             if (other.roleId != null)  
  71.                 return false;  
  72.         } else if (!roleId.equals(other.roleId))  
  73.             return false;  
  74.         return true;  
  75.     }  
  76.   
  77. }  

如果需要*.hbm.xml则进行配置。


四、写自定义拦截器

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import javax.servlet.http.HttpServletRequest;  
  2. import org.apache.struts2.ServletActionContext;  
  3. import com.opensymphony.xwork2.ActionInvocation;  
  4. import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;  
  5.   
  6. /** 
  7.  * 自定义拦截器 
  8.  * @author grace 
  9.  * 
  10.  */  
  11. @SuppressWarnings("serial")  
  12. public class LimitInterceptor  extends MethodFilterInterceptor{  
  13.   
  14.     public String doIntercept(ActionInvocation invocation) throws Exception {  
  15.         //获取请求的action对象  
  16.         Object action=invocation.getAction();  
  17.           
  18.         //获取请求的方法的名称  
  19.         String methodName=invocation.getProxy().getMethod();  
  20.           
  21.         //获取action中的方法的封装类(action中的方法没有参数)  
  22.         Method method=action.getClass().getMethod(methodName, null);  
  23.   
  24.         //获取request对象  
  25.         HttpServletRequest request=ServletActionContext.getRequest();  
  26.           
  27.         //检查注解  
  28.         boolean flag=isCheckLimit(request,method);  
  29.           
  30.         if(!flag){  
  31.             //没有权限,通过struts2转到事先定义好的页面  
  32.             return "popmsg_popedom";  
  33.         }  
  34.           
  35.         //有权限,可以调用action中的方法  
  36.         String returnvalue=invocation.invoke();  
  37.         return returnvalue;  
  38.     }  
  39.   
  40.     public boolean isCheckLimit(HttpServletRequest request, Method method) {  
  41.         if(method==null){  
  42.             return false;  
  43.         }  
  44.           
  45.         //获取当前的登陆用户  
  46.         SysUser sysUser=SessionUtils.getSysUserFormSession(request);  
  47.         if(sysUser==null){  
  48.             return false;  
  49.         }  
  50.         //如果用户的权限组为空  
  51.         if(sysUser.getSysRole()==null){  
  52.             return false;  
  53.         }  
  54.           
  55.         //获取当前登陆用户的权限组id  
  56.         String roleId=sysUser.getSysRole().getId();  
  57.         //处理注解  
  58.         /* 
  59.          *  @Limit(module="group",privilege="list") 
  60.             public String list(){ 
  61.                 .... 
  62.             } 
  63.          */  
  64.         //判断用户请求的method上面是否存在注解  
  65.         boolean isAnnotationPresent= method.isAnnotationPresent(Limit.class);  
  66.           
  67.         //不存在注解  
  68.         if(!isAnnotationPresent){  
  69.             return false;  
  70.         }  
  71.           
  72.         //存在注解,拿到由Limit类写的注解  
  73.         Limit limit=method.getAnnotation(Limit.class);  
  74.           
  75.         //获取注解上的值  
  76.         String module=limit.module();  //模块名称  
  77.         String privilege=limit.privilege(); //操作名称  
  78.           
  79.         /** 
  80.          * 如果登陆用户的权限组id+注解上的@Limit(module="group",privilege="list") 
  81.          *   * 在sys_popedom_privilege表中存在   flag=true; 
  82.          *   * 在sys_popedom_privilege表中不存在 flag=false; 
  83.          */  
  84.         boolean flag=false;  
  85.           
  86.         //通过自己封装的方法拿到操作权限的业务层对象  
  87.         ISysPopedomPrivilegeService sysPopedomPrivilegeService=  
  88.             (ISysPopedomPrivilegeService)ServiceProvinder.getService(ISysPopedomPrivilegeService.SERVICE_NAME);  
  89.           
  90.         //查询sys_popedom_privilege表中的所有的数据  
  91.         //因为后面用到二级缓存,因此这里直接查询出所有的操作权限,而不是通过登陆用户的权限组来查询  
  92.         List<SysPopedomPrivilege> list=sysPopedomPrivilegeService.findAllSysPopedomPrivileges();  
  93.           
  94.         if(list!=null&&list.size()>0){  
  95.           for(int i=0;i<list.size();i++){  
  96.               SysPopedomPrivilege s=list.get(i);  
  97.               if(s!=null){  
  98.                   //判断登陆用户是否拥有该方法的权限:如果登陆用户的roleId和登陆用户访问的方法  
  99.                   //的注释中的module和privilege(例如@Limit(module="group",privilege="list")),这三个字段  
  100.                   //在sys_popedom_privilege表中有记录与之对应,则代表该用户拥有权限访问此方法  
  101.                    if(roleId.equals(s.getId().getRoleId())&&module.equals(s.getId().getPopedomModule())  
  102.                            &&privilege.equals(s.getId().getPopedomPrivilege())){  
  103.                        flag=true;  
  104.                        break;  
  105.                    }  
  106.               }  
  107.           }  
  108.         }  
  109.         return flag;  
  110.     }  
  111. }  


五、在struts.xml中配置自定义拦截器和没有权限时访问的页面。

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <interceptors>  
  2.     <!-- 声明拦截器 -->  
  3.     <interceptor name="limitInterceptor" class="cn.grace.interceptor.LimitInterceptor"></interceptor>  
  4.     <interceptor-stack name="limitStack">  
  5.         <interceptor-ref name="defaultStack" />  
  6.         <interceptor-ref name="limitInterceptor">  
  7.             <!-- 配置不被拦截的方法 -->  
  8.             <param name="excludeMethods">isLogin,logout,top,left</param>  
  9.         </interceptor-ref>  
  10.     </interceptor-stack>  
  11. </interceptors>  
  12. <!-- struts2运行时,执行的拦截器栈 -->  
  13. <default-interceptor-ref name="limitStack" />  
  14.     
  15.   <global-results>  
  16.         <!-- 转发到没有权限的页面 -->  
  17.         <result name="popmsg_popedom">/WEB-INF/page/popmsg_popedom.jsp</result>  
  18.   </global-results>  

六、通过在Action的方法中进行注释,实现权限控制。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import cn.grace.annotation.Limit;  
  2.   
  3. public class testUserAction {  
  4.   
  5.     /** 用户添加页面 */  
  6.     @Limit(module="user",privilege="add")  
  7.     public String add(){  
  8.         return "add";  
  9.     }  
  10.       
  11.     /** 用户添加 **/  
  12.     @Limit(module="user",privilege="save")  
  13.     public String save(){  
  14.         return "save";  
  15.     }  
  16.       
  17.     /** 用户删除 **/  
  18.     @Limit(module="user",privilege="delete")  
  19.     public String delete(){  
  20.         return "delete";  
  21.     }  
  22.       
  23.     /** 用户修改页面 **/  
  24.     @Limit(module="user",privilege="edit")  
  25.     public String edit() {  
  26.         return "edit";  
  27.     }  
  28.       
  29.     /** 用户修改  **/  
  30.     @Limit(module="user",privilege="update")  
  31.     public String update() {  
  32.         return "update";  
  33.     }  
  34.   
  35.     /** 用户列表 (查询) */  
  36.     @Limit(module="user",privilege="list")  
  37.     public String list() {  
  38.         return "list";  
  39.     }  
  40. }  
至此,权限控制实现完毕。


七、整个权限控制的功能实现概要为:

例子:3个不同权限的用户

1.系统管理的权限id(roleId)为:8af0897545e4c91b0145e4cd385d0002;而在sys_popedom_privilege表中,roleId为:8af0897545e4c91b0145e4cd385d0002,拥有所有模块和操作,则系统管理员拥有所有模块的所有操作权限。


2.部门经理的权限id(roleId)为:8af09d7845fe6ef90145fe70a0a80001;而在sys_popedom_privilege表中,roleId为:8af09d7845fe6ef90145fe70a0a80001,拥有部门模块的所有操作(9个),则部门经理拥有部门模块的所有9个操作权限,但没有其他(例如city和code模块)模块的操作权限。



3.小明的权限id(roleId)为:8af0897545e4c91b0145e4cd65b30003;而在sys_popedom_privilege表中,roleId为:8af0897545e4c91b0145e4cd65b30003,仅拥有部门模块的部分操作(比部门经理比少了list和edit操作),则小明拥有部门模块下的部分操作权限。如下图,其中roleId为8af0897545e4c91b0145e4cd65b30003对应的模块和操作只有下图前7行。




总结:自定义拦截器类会将当前登陆用户的roleId(上文中没有给出User表)和用户要访问的方法的@Limit注释中的module和privilege,共三个字段,与sys_popedom_privilege表中的三个字段进行比较,存在相应的记录,则表示用户有权限。否则,代表用户没有权限。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值