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

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

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

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


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表中的三个字段进行比较,存在相应的记录,则表示用户有权限。否则,代表用户没有权限。


相关文章
|
10月前
SpringMVC拦截器的介绍,拦截器的基本实现,拦截器链配置
SpringMVC拦截器的介绍,拦截器的基本实现,拦截器链配置
93 2
|
安全 Java 数据库连接
【springMvc】自定义注解的使用方式
【springMvc】自定义注解的使用方式
131 0
|
10月前
swagger被拦截器拦截
swagger被拦截器拦截
208 0
|
10月前
|
前端开发 Java 应用服务中间件
掌握Spring MVC拦截器整合技巧,实现灵活的请求处理与权限控制!
掌握Spring MVC拦截器整合技巧,实现灵活的请求处理与权限控制!
|
前端开发 Java 数据库
SpringSecurity非注解方式进行权限控制
写在前面 本文是使用SpringSecurity进行权限控制,此次项目没有采用SpringSecurity的注解形式,因为当你使用SpringSecurity注解形式进行权限控制的时候,当你给一个接口定义了注解过后,那么这个接口所对应的角色也就固定了,如果要修改启动的项目,只有重新修改代码,然后进行部署,本次演示是通过查询数据权限来获取对应的角色来进行匹配是否放行
265 2
SpringSecurity非注解方式进行权限控制
|
缓存 开发框架 安全
AOP的另类用法 (权限校验&&自定义注解)
告别了OOP编程, 迎来了一个新的AOP编程时代👍👍👍, 最近有同学问我AOP除了写日志还能干什么, 其实AOP能干的事情挺多的, 可能只是他们写的代码中暂时用不到. 其实如果当我们写一些简单的程序的时候, SpringSecurity完全用不到的时候, 就可以使用AOP与自定义注解来为角色的访问权限进行鉴定, 绝对比Security更轻量👉👉👉 我们在接触框架的时候经常会用到注解, 但是我们自己自定义注解的情况比较少, 一般都是配合切面编程使用, 一起来看看吧
226 0
|
前端开发 Java 数据安全/隐私保护
SpringMVC拦截器实现登录权限控制
SpringMVC的处理器拦截器,类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。 依赖于web框架,在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于 web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个 controller生命周期之内可以多次调用。
SpringMVC 如何使用注解完成登录拦截
SpringMVC 如何使用注解完成登录拦截
SpringMVC 如何使用注解完成登录拦截
|
安全 Java 数据库
SpringBoot+拦截器+自定义异常+自定义注解+全局异常处理简单实现接口权限管理
提到权限管理这块肯定很多人第一想到的就是Springboot Security或者是Shiro安全框架,但本文介绍的并不是这两种,不是因为他们不好用,实在是自己太懒了,我觉得一个拦截器加上其他的一些处理就能满足项目的需求,我又何必去多用一个框架呢,这篇文章也不是去对比谁好谁坏,各位自行抉择。
84136 6
|
Java 应用服务中间件 调度
SpringMVC——核心技术:拦截器(一个/多个、权限拦截器)
SpringMVC——核心技术:拦截器(一个/多个、权限拦截器)
SpringMVC——核心技术:拦截器(一个/多个、权限拦截器)