开发者社区> 程序员囧辉> 正文

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

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

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

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


import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
 
/**
 * 自定义注解
 * @author grace
 *
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface Limit{
     String module();  //模块名称
     String privilege(); //操作名称
}


二、建好所需要的表


#权限组表
CREATE TABLE `sys_role` (
  `id` varchar(36),                             #编号
  `remark` TEXT,                                #备注
  `name` VARCHAR(100)  DEFAULT NULL,             #名称
  PRIMARY KEY (`id`)
)
#操作表
CREATE TABLE sys_popedom
(
   popedomModule       VARCHAR(30),                              #模块名称
   popedomPrivilege    VARCHAR(30),                              #操作名称
   sort                INTEGER(11),                              #排序
   title               VARCHAR(200),                             #提示
   popedomName         VARCHAR(200),                             #标题
   remark              TEXT,                                     #说明
   PRIMARY KEY(popedomModule,popedomPrivilege)
)
#操作权限表
CREATE TABLE sys_popedom_privilege
(
   roleId         VARCHAR(36),        #权限组编号
   popedomModule     VARCHAR(30),     #模块名称
   popedomPrivilege  VARCHAR(30),     #操作名称
   PRIMARY KEY(roleId,popedomModule,popedomPrivilege)
)

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


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


image.png


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

image.png


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

image.png

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


权限组表:

/*
 * SysRole:权限组表
 */
@SuppressWarnings("serial")
public class SysRole implements java.io.Serializable {
    private String id;
    private String name;
    private String remark;
 
    public String getId() {
        return id;
    }
 
    public void setId(String id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getRemark() {
        return remark;
    }
 
    public void setRemark(String remark) {
        this.remark = remark;
    }
 
}

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


操作表:

/*
 * 操作表
 */
@SuppressWarnings("serial")
public class SysPopedom  implements java.io.Serializable{
/*
 * CREATE TABLE sys_popedom
(
   popedomModule       VARCHAR(30),                              #模块名称
   popedomPrivilege    VARCHAR(30),                              #操作名称
   sort                INTEGER(11),                              #排序
   title               VARCHAR(200),                             #提示
   popedomName         VARCHAR(200),                             #标题
   remark              TEXT,                                     #说明
   PRIMARY KEY(popedomModule,popedomPrivilege)
)
 */
    private SysPopedomId id;//主键 OID
    private Integer sort;
    private String title;
    private String popedomName;
    private String remark;
    
    public SysPopedomId getId() {
        return id;
    }
    public void setId(SysPopedomId id) {
        this.id = id;
    }
    public Integer getSort() {
        return sort;
    }
    public void setSort(Integer sort) {
        this.sort = sort;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getPopedomName() {
        return popedomName;
    }
    public void setPopedomName(String popedomName) {
        this.popedomName = popedomName;
    }
    public String getRemark() {
        return remark;
    }
    public void setRemark(String remark) {
        this.remark = remark;
    }
    
}
/**
 * 操作表中的联合主键类
 * @author grace
 *
 */
@SuppressWarnings("serial")
public class SysPopedomId implements java.io.Serializable {
    private String popedomModule;
    private String popedomPrivilege;
 
    public String getPopedomModule() {
        return popedomModule;
    }
    
    public void setPopedomModule(String popedomModule) {
        this.popedomModule = popedomModule;
    }
 
    public String getPopedomPrivilege() {
        return popedomPrivilege;
    }
 
    public void setPopedomPrivilege(String popedomPrivilege) {
        this.popedomPrivilege = popedomPrivilege;
    }
 
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((popedomModule == null) ? 0 : popedomModule.hashCode());
        result = prime
                * result
                + ((popedomPrivilege == null) ? 0 : popedomPrivilege.hashCode());
        return result;
    }
 
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        final SysPopedomId other = (SysPopedomId) obj;
        if (popedomModule == null) {
            if (other.popedomModule != null)
                return false;
        } else if (!popedomModule.equals(other.popedomModule))
            return false;
        if (popedomPrivilege == null) {
            if (other.popedomPrivilege != null)
                return false;
        } else if (!popedomPrivilege.equals(other.popedomPrivilege))
            return false;
        return true;
    }
}

操作权限表:

/**
 * 操作权限表
 * @author grace
 *
 */
@SuppressWarnings("serial")
public class SysPopedomPrivilege implements java.io.Serializable {
    /*
     * CREATE TABLE sys_popedom_privilege 
     * ( 
     *   roleId VARCHAR(36), #权限组编号
     *   popedomModule VARCHAR(30), #模块名称 
     *   popedomPrivilege VARCHAR(30), #操作名称
     *   PRIMARY KEY(roleId,popedomModule,popedomPrivilege) 
     * )
     */
 
    private SysPopedomPrivilegeId id;
 
    public SysPopedomPrivilegeId getId() {
        return id;
    }
 
    public void setId(SysPopedomPrivilegeId id) {
        this.id = id;
    }
 
}
/**
 * 操作权限表的联合主键类
 * @author grace
 *
 */
@SuppressWarnings("serial")
public class SysPopedomPrivilegeId implements java.io.Serializable {
 
    private String roleId;
    private String popedomModule;
    private String popedomPrivilege;
 
    public String getRoleId() {
        return roleId;
    }
 
    public void setRoleId(String roleId) {
        this.roleId = roleId;
    }
 
    public String getPopedomModule() {
        return popedomModule;
    }
 
    public void setPopedomModule(String popedomModule) {
        this.popedomModule = popedomModule;
    }
 
    public String getPopedomPrivilege() {
        return popedomPrivilege;
    }
 
    public void setPopedomPrivilege(String popedomPrivilege) {
        this.popedomPrivilege = popedomPrivilege;
    }
 
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((popedomModule == null) ? 0 : popedomModule.hashCode());
        result = prime
                * result
                + ((popedomPrivilege == null) ? 0 : popedomPrivilege.hashCode());
        result = prime * result + ((roleId == null) ? 0 : roleId.hashCode());
        return result;
    }
 
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        final SysPopedomPrivilegeId other = (SysPopedomPrivilegeId) obj;
        if (popedomModule == null) {
            if (other.popedomModule != null)
                return false;
        } else if (!popedomModule.equals(other.popedomModule))
            return false;
        if (popedomPrivilege == null) {
            if (other.popedomPrivilege != null)
                return false;
        } else if (!popedomPrivilege.equals(other.popedomPrivilege))
            return false;
        if (roleId == null) {
            if (other.roleId != null)
                return false;
        } else if (!roleId.equals(other.roleId))
            return false;
        return true;
    }
 
}

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


四、写自定义拦截器


import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
 
/**
 * 自定义拦截器
 * @author grace
 *
 */
@SuppressWarnings("serial")
public class LimitInterceptor  extends MethodFilterInterceptor{
 
    public String doIntercept(ActionInvocation invocation) throws Exception {
        //获取请求的action对象
        Object action=invocation.getAction();
        
        //获取请求的方法的名称
        String methodName=invocation.getProxy().getMethod();
        
        //获取action中的方法的封装类(action中的方法没有参数)
        Method method=action.getClass().getMethod(methodName, null);
 
        //获取request对象
        HttpServletRequest request=ServletActionContext.getRequest();
        
        //检查注解
        boolean flag=isCheckLimit(request,method);
        
        if(!flag){
            //没有权限,通过struts2转到事先定义好的页面
            return "popmsg_popedom";
        }
        
        //有权限,可以调用action中的方法
        String returnvalue=invocation.invoke();
        return returnvalue;
    }
 
    public boolean isCheckLimit(HttpServletRequest request, Method method) {
        if(method==null){
            return false;
        }
        
        //获取当前的登陆用户
        SysUser sysUser=SessionUtils.getSysUserFormSession(request);
        if(sysUser==null){
            return false;
        }
        //如果用户的权限组为空
        if(sysUser.getSysRole()==null){
            return false;
        }
        
        //获取当前登陆用户的权限组id
        String roleId=sysUser.getSysRole().getId();
        //处理注解
        /*
         *  @Limit(module="group",privilege="list")
            public String list(){
                ....
            }
         */
        //判断用户请求的method上面是否存在注解
        boolean isAnnotationPresent= method.isAnnotationPresent(Limit.class);
        
        //不存在注解
        if(!isAnnotationPresent){
            return false;
        }
        
        //存在注解,拿到由Limit类写的注解
        Limit limit=method.getAnnotation(Limit.class);
        
        //获取注解上的值
        String module=limit.module();  //模块名称
        String privilege=limit.privilege(); //操作名称
        
        /**
         * 如果登陆用户的权限组id+注解上的@Limit(module="group",privilege="list")
         *   * 在sys_popedom_privilege表中存在   flag=true;
         *   * 在sys_popedom_privilege表中不存在 flag=false;
         */
        boolean flag=false;
        
        //通过自己封装的方法拿到操作权限的业务层对象
        ISysPopedomPrivilegeService sysPopedomPrivilegeService=
            (ISysPopedomPrivilegeService)ServiceProvinder.getService(ISysPopedomPrivilegeService.SERVICE_NAME);
        
        //查询sys_popedom_privilege表中的所有的数据
        //因为后面用到二级缓存,因此这里直接查询出所有的操作权限,而不是通过登陆用户的权限组来查询
        List<SysPopedomPrivilege> list=sysPopedomPrivilegeService.findAllSysPopedomPrivileges();
        
        if(list!=null&&list.size()>0){
          for(int i=0;i<list.size();i++){
              SysPopedomPrivilege s=list.get(i);
              if(s!=null){
                  //判断登陆用户是否拥有该方法的权限:如果登陆用户的roleId和登陆用户访问的方法
                  //的注释中的module和privilege(例如@Limit(module="group",privilege="list")),这三个字段
                  //在sys_popedom_privilege表中有记录与之对应,则代表该用户拥有权限访问此方法
                   if(roleId.equals(s.getId().getRoleId())&&module.equals(s.getId().getPopedomModule())
                           &&privilege.equals(s.getId().getPopedomPrivilege())){
                       flag=true;
                       break;
                   }
              }
          }
        }
        return flag;
    }
}


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


<interceptors>
    <!-- 声明拦截器 -->
    <interceptor name="limitInterceptor" class="cn.grace.interceptor.LimitInterceptor"></interceptor>
    <interceptor-stack name="limitStack">
  <interceptor-ref name="defaultStack" />
  <interceptor-ref name="limitInterceptor">
    <!-- 配置不被拦截的方法 -->
    <param name="excludeMethods">isLogin,logout,top,left</param>
  </interceptor-ref>
    </interceptor-stack>
</interceptors>
<!-- struts2运行时,执行的拦截器栈 -->
<default-interceptor-ref name="limitStack" />
 
  <global-results>
    <!-- 转发到没有权限的页面 -->
    <result name="popmsg_popedom">/WEB-INF/page/popmsg_popedom.jsp</result>
  </global-results>

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


import cn.grace.annotation.Limit;
 
public class testUserAction {
 
    /** 用户添加页面 */
    @Limit(module="user",privilege="add")
    public String add(){
        return "add";
    }
    
    /** 用户添加 **/
    @Limit(module="user",privilege="save")
    public String save(){
        return "save";
    }
    
    /** 用户删除 **/
    @Limit(module="user",privilege="delete")
    public String delete(){
        return "delete";
    }
    
    /** 用户修改页面 **/
    @Limit(module="user",privilege="edit")
    public String edit() {
        return "edit";
    }
    
    /** 用户修改  **/
    @Limit(module="user",privilege="update")
    public String update() {
        return "update";
    }
 
    /** 用户列表 (查询) */
    @Limit(module="user",privilege="list")
    public String list() {
        return "list";
    }
}

至此,权限控制实现完毕。



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

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

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




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


image.png




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

image.png





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


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
29064 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
16411 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
20681 0
腾讯云服务器 设置ngxin + fastdfs +tomcat 开机自启动
在tomcat中新建一个可以启动的 .sh 脚本文件 /usr/local/tomcat7/bin/ export JAVA_HOME=/usr/local/java/jdk7 export PATH=$JAVA_HOME/bin/:$PATH export CLASSPATH=.
14896 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
23576 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
22330 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
36416 0
+关注
程序员囧辉
全网同名,主要在B站和公众号分享。内容:大厂高并发项目案例、高频面试题、经验分享
183
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载