一种基于注解的Spring MVC权限控制方法

jopen 7年前

简介

本文介绍一种采用annotation来对spring-mvc进行权限控制的方法. 通过枚举类来定义权限项. 将annotation标注到需要控制权限的spring-mvc方法上. 然后,在spring-mvc中定义全局过滤器, 过滤所有spring-mvc方法, 查看方法上的权限annotation信息, 以此对权限进行控制.

优点

编写比较方便, 在需要控制权限的方法上进行annotation的标注即可, ide能够对annotation进行识别支持. 查看权限配置比较方便, 因为annotation就在方法上, 不用去其他地方翻看. 实现方式比较简单.

具体实现

1.建立权限枚举类

建立权限枚举类型, 用于描述权限的种类, 包含了权限的名称. 每个枚举值中包含了权限中文名称和权限索引值(即权限位). (思考:是否可以直接用中文名称作为枚举值的名称,我在其他程序已经用了中文枚举名称了,暂时没有遇到问题)

public enum AuthorityType{  // 包含了枚举的中文名称, 枚举的索引值  WORKER("增删改查员工", 1),    SALES_ORDER_CREATE("创建订单", 6),   SALES_ORDER_FIND("查看订单", 7),  SALES_ORDER_MODIFY("修改订单", 8),  SALES_ORDER_DELETE("删除订单", 9),  ;  private String name;  private int index;    private AuthorityType(String name, int index) {      this.name = name;      this.index = index;  }  public String getName() {      return name;  }  public void setName(String name) {      this.name = name;  }  public int getIndex() {      return index;  }  public void setIndex(int index) {      this.index = index;  }  }

2.登录方式的枚举类

登录方式的枚举类, page代表传统登录页面, json表示ajax的登录

public enum ResultTypeEnum {  //整页刷新  page,   //json数据  json  }

3.建立表示权限annotation类

建立annotation类, 用于标注到需要权限验证的地方

import java.lang.annotation.Documented;  import java.lang.annotation.ElementType;  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy;  import java.lang.annotation.Target;    @Target(ElementType.METHOD)  @Retention(RetentionPolicy.RUNTIME)  @Documented  public @interface FireAuthority {      AuthorityType[] authorityTypes();      ResultTypeEnum resultType() default ResultTypeEnum.page;  }

4.在user类中加入权限字段

在user用户类中添加文本字段表示权限, 字段长度为250字符(因为mysql默认255个字符,可以代表250个权限应该够用了), 字符内容是0或者1. 1表示有权限, 0表示无权限. 提示: 对于用户的权限配置, 只要将对应的权限位设置为0或者1即可.

create table user (          id integer not null auto_increment,          name varchar(255),          right_content varchar(255),          primary key (id)      ) type=InnoDB

5.权限验证算法

权限判断方法, 权限判断的实现算法, 用于判断是否有权限

public class AuthorityHelper {    /**   * 判断是否有权限   * @param akey  aString中位置的索引值,也就是权限位   * @param aString  权限字段,比如 11010101011101   * @return   */  public static boolean hasAuthority(int akey,String aString){      return ConstanHelper.getAuthorityVaule(akey,rc);      if(aString==null || "".equals(aString)){          return false;      }        char value = aString.charAt(akey);      if(value == '1'){          return true;      }        return false;    }    }

6.建立控制权限的interceptor类

建立interceptor类, 用于过滤需要控制权限的方法.

import java.io.OutputStream;  import java.io.OutputStreamWriter;  import java.io.PrintWriter;  import java.net.URLEncoder;  import javax.servlet.http.HttpServletRequest;  import javax.servlet.http.HttpServletResponse;  import javax.servlet.http.HttpSession;  import org.slf4j.Logger;  import org.slf4j.LoggerFactory;  import org.springframework.web.method.HandlerMethod;  import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;    public class AuthorityAnnotationInterceptor extends HandlerInterceptorAdapter {        final Logger logger = LoggerFactory.getLogger(getClass());        @Override      public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {          logger.debug("");          HandlerMethod handler2=(HandlerMethod) handler;          FireAuthority fireAuthority = handler2.getMethodAnnotation(FireAuthority.class);            if(null == fireAuthority){              //没有声明权限,放行              return true;          }            logger.debug("fireAuthority", fireAuthority.toString());            HttpSession session = request.getSession();          Worker manager = (Worker)session.getAttribute(SessionHelper.WorkerHandler);          boolean aflag = false;            for(AuthorityType at:fireAuthority.authorityTypes()){              if(AuthorityHelper.hasAuthority(at.getIndex(), manager.getRightContent())==true){                  aflag = true;                  break;              }          }            if(false == aflag){                if (fireAuthority.resultType() == ResultTypeEnum.page) {                  //传统的登录页面                                 StringBuilder sb = new StringBuilder();                  sb.append(request.getContextPath());                  sb.append("/oprst.jsp?oprst=false&opmsg=").append(URLEncoder.encode(ControllerProperty.NOT_HAVE_AUTHORITY,"utf-8"));                  response.sendRedirect(sb.toString());              } else if (fireAuthority.resultType() == ResultTypeEnum.json) {                  //ajax类型的登录提示                  response.setCharacterEncoding("utf-8");                  response.setContentType("text/html;charset=UTF-8");                  OutputStream out = response.getOutputStream();                  PrintWriter pw = new PrintWriter(new OutputStreamWriter(out,"utf-8"));                  pw.println("{\"result\":false,\"code\":12,\"errorMessage\":\""+ControllerProperty.NOT_HAVE_AUTHORITY+"\"}");                  pw.flush();                  pw.close();              }                return false;            }          return true;      }    }

7.配置interceptor类

在spring-mvc中配置interceptor, 实现过滤.

<mvc:interceptors>          <bean class="interceptor.AuthorityAnnotationInterceptor"></bean>      </mvc:interceptors>

8.标注需要控制权限的方法

在需要控制访问的spring-mvc方法上面加上对应的标注.
//方式一

@FireAuthority(AuthorityType. SALES_ORDER_CREATE)  @RequestMapping(value="/save.spr", method=RequestMethod.POST)  public ModelAndView save(String  name) throws Exception {      //some code  }

//方式二

@FireAuthority(authorityTypes = {AuthorityType.SALES_ORDER_DELETE,AuthorityType.SALES_ORDER_CREATE})      @RequestMapping(value="/save.spr", method=RequestMethod.POST)      public ModelAndView save(String  name) throws Exception {          //some code      }

//方式三

@FireAuthority(authorityTypes = AuthorityType.SALES_ORDER_DELETE, resultType=ResultTypeEnum.page)  @RequestMapping(value="/save.spr", method=RequestMethod.POST)  public ModelAndView save(String  name) throws Exception {      //some code  }

9.完成了