• SpringMVC拦截器+Spring自定义注解实现权限验证


    特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过。如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/mao2080/

    设计思路

    主要针对需要登录后操作的接口进行校验。接入层在对外暴露接口后,网页、APP、第三方等等途径进行访问接口。用户请求首先会被SpringMVC拦截器拦截到,在拦截器里第一步就是需要校验用户的登录身份(由于是分布式系统这里采用的是userId+accessToken方式来校验),登录校验通过之后再进行用户权限校验,此时会自动拦截@AuthValidate注解的method(核心),如果权限校验失败则抛出权限不足异常,否则校验通过之后再执行具体接口并返回结果。

    1、自定义注解

     1 package com.mao.auth;
     2 import java.lang.annotation.Documented;
     3 import java.lang.annotation.ElementType;
     4 import java.lang.annotation.Retention;
     5 import java.lang.annotation.RetentionPolicy;
     6 import java.lang.annotation.Target;
     7 
     8 /**
     9  * 
    10  * 项目名称:---
    11  * 模块名称:接入层
    12  * 功能描述:权限定义
    13  * 创建人: mao2080@sina.com
    14  * 创建时间:2017年5月9日 下午8:41:05
    15  * 修改人: mao2080@sina.com
    16  * 修改时间:2017年5月9日 下午8:41:05
    17  */
    18 @Target(value = ElementType.METHOD)
    19 @Retention(value = RetentionPolicy.RUNTIME)
    20 @Documented
    21 public @interface AuthValidate {
    22     
    23     /**
    24      * 
    25      * 描述:权限定义
    26      * @author mao2080@sina.com
    27      * @created 2017年5月8日 上午11:36:41
    28      * @since 
    29      * @return 权限代码
    30      */
    31     AuthCode value() default AuthCode.Allow;
    32     
    33 }

    2、权限枚举

      1 package com.mao.auth;
      2 
      3 /**
      4  * 
      5  * 项目名称:---
      6  * 模块名称:接入层
      7  * 功能描述:权限类型枚举
      8  * 创建人: mao2080@sina.com
      9  * 创建时间:2017年5月8日 上午11:43:12
     10  * 修改人: mao2080@sina.com
     11  * 修改时间:2017年5月8日 上午11:43:12
     12  */
     13 public enum AuthCode {
     14     
     15     Allow("00000", "00000", "允许访问"),
     16     
     17     /******************客户权限******************/
     18     
     19     AU0001("100001", "AU0001", "新增用户", "新增用户"),
     20     
     21     AU0002("100002", "AU0002", "删除用户", "批量删除用户");
     22     
     23     /**权限标识 */
     24     private String authId;
     25     
     26     /**权限编码 */
     27     private String authCode;
     28     
     29     /**权限名称 */
     30     private String authName;
     31     
     32     /**权限描述 */
     33     private String authDesc;
     34     
     35     /**
     36      * 
     37      * 描述:构建设备类型
     38      * @author mao2080@sina.com
     39      * @created 2017年3月22日 上午13:50:58
     40      * @since 
     41      * @param authId 权限标识
     42      * @param authCode 权限编码
     43      * @param authName 权限名称
     44      * @return
     45      */
     46     private AuthCode(String authId, String authCode, String authName) {
     47         this.authId = authId;
     48         this.authCode = authCode;
     49         this.authName = authName;
     50     }
     51     
     52     /**
     53      * 
     54      * 描述:构建设备类型
     55      * @author mao2080@sina.com
     56      * @created 2017年3月22日 上午13:50:58
     57      * @since 
     58      * @param authId 权限标识
     59      * @param authCode 权限编码
     60      * @param authName 权限名称
     61      * @param authDesc 权限描述
     62      * @return
     63      */
     64     private AuthCode(String authId, String authCode, String authName, String authDesc) {
     65         this.authId = authId;
     66         this.authCode = authCode;
     67         this.authName = authName;
     68         this.authDesc = authDesc;
     69     }
     70     
     71     public String getAuthId() {
     72         return authId;
     73     }
     74 
     75     public void setAuthId(String authId) {
     76         this.authId = authId;
     77     }
     78 
     79     public String getAuthCode() {
     80         return authCode;
     81     }
     82 
     83     public void setAuthCode(String authCode) {
     84         this.authCode = authCode;
     85     }
     86 
     87     public String getAuthDesc() {
     88         return authDesc;
     89     }
     90 
     91     public void setAuthDesc(String authDesc) {
     92         this.authDesc = authDesc;
     93     }
     94     
     95     public String getAuthName() {
     96         return authName;
     97     }
     98 
     99     public void setAuthName(String authName) {
    100         this.authName = authName;
    101     }
    102 
    103     @Override
    104     public String toString() {
    105         return String.format("authId:%s, authCode:%s, authName:%s, authDesc:%s", this.authId, this.authCode, this.authName, this.authDesc);
    106     }
    107 
    108 }

    3、Controller使用自定义注解

     1 package com.mao.controller;
     2 
     3 import javax.servlet.http.HttpServletRequest;
     4 
     5 import org.apache.commons.logging.Log;
     6 import org.apache.commons.logging.LogFactory;
     7 import org.springframework.stereotype.Controller;
     8 import org.springframework.web.bind.annotation.RequestMapping;
     9 import org.springframework.web.bind.annotation.ResponseBody;
    10 
    11 import com.mao.auth.AuthCode;
    12 import com.mao.auth.AuthValidate;
    13 import com.mao.beans.ResObject;
    14 import com.mao.exception.BusinessException;
    15 
    16 /**
    17  * 
    18  * 项目名称:---
    19  * 模块名称:接入层
    20  * 功能描述:用户控制层
    21  * 创建人: mao2080@sina.com
    22  * 创建时间:2017年5月9日 下午8:15:50
    23  * 修改人: mao2080@sina.com
    24  * 修改时间:2017年5月9日 下午8:15:50
    25  */
    26 @Controller
    27 @RequestMapping("/userController")
    28 public class UserController {
    29 
    30     /**日志*/
    31     @SuppressWarnings("unused")
    32     private static final Log loger = LogFactory.getLog(UserController.class);
    33     
    34      /**
    35       * 
    36       * 描述:新增用户
    37       * @author mao2080@sina.com
    38       * @created 2017年5月9日 下午8:16:41
    39       * @since 
    40       * @param request
    41       * @return
    42       * @throws BusinessException
    43       */
    44     @RequestMapping("/createUser")
    45     @ResponseBody
    46     @AuthValidate(AuthCode.AU0001)
    47     public ResObject createUser(HttpServletRequest request) throws BusinessException{
    48         //业务代码
    49         return new ResObject();
    50     }
    51     
    52     /**
    53       * 
    54       * 描述:新增用户
    55       * @author mao2080@sina.com
    56       * @created 2017年5月9日 下午8:16:41
    57       * @since 
    58       * @param request
    59       * @return
    60       * @throws BusinessException
    61       */
    62     @RequestMapping("/deleteUser")
    63     @ResponseBody
    64     @AuthValidate(AuthCode.AU0002)
    65     public ResObject deleteUser(HttpServletRequest request) throws BusinessException{
    66         //业务代码
    67         return new ResObject();
    68     }
    69 }

    4、SpringMVC拦截器

      1 package com.mao.interceptor;
      2 import java.io.PrintWriter;
      3 import java.util.ArrayList;
      4 import java.util.List;
      5 
      6 import javax.servlet.http.HttpServletRequest;
      7 import javax.servlet.http.HttpServletResponse;
      8 
      9 import org.springframework.web.method.HandlerMethod;
     10 import org.springframework.web.servlet.HandlerInterceptor;
     11 import org.springframework.web.servlet.ModelAndView;
     12 
     13 import com.mao.auth.AuthCode;
     14 import com.mao.auth.AuthValidate;
     15 import com.mao.exception.BusinessException;
     16 import com.mao.util.JsonUtil;
     17 
     18 /**
     19  * 
     20  * 项目名称:---
     21  * 模块名称:接入层
     22  * 功能描述:用户登录拦截器(利用SpringMVC自定义拦截器实现)
     23  * 创建人: mao2080@sina.com
     24  * 创建时间:2017年4月25日 下午8:53:49
     25  * 修改人: mao2080@sina.com
     26  * 修改时间:2017年4月25日 下午8:53:49
     27  */
     28 public class UserLoginInterceptor implements HandlerInterceptor {
     29     
     30     /**
     31      * 
     32      * 描述:构造函数
     33      * @author mao2080@sina.com
     34      * @created 2017年4月28日 下午5:20:34
     35      * @since 
     36      * @param accessService
     37      */
     38     public UserLoginInterceptor() {
     39         
     40     }
     41 
     42     /**
     43      * 
     44      * 描述:执行方法前
     45      * @author mao2080@sina.com
     46      * @created 2017年4月25日 下午9:01:44
     47      * @since 
     48      * @param request HttpServletRequest
     49      * @param response HttpServletResponse
     50      * @param handler handler
     51      * @return
     52      * @throws Exception
     53      */
     54     @Override
     55     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
     56         try {
     57             //校验登录
     58             this.userLoginValidate(request);
     59             //校验权限
     60             this.userAuthValidate(request, handler);
     61         } catch (Exception e) {
     62             e.printStackTrace();
     63             printMessage(response, e);
     64             return false;
     65         }
     66         return true;
     67     }
     68     
     69     /**
     70      * 
     71      * 描述:输出到前端
     72      * @author mao2080@sina.com
     73      * @created 2017年4月28日 上午11:00:25
     74      * @since 
     75      * @param response 响应
     76      * @param res 对象
     77      * @throws Exception
     78      */
     79     public static void printMessage(HttpServletResponse response, Object res) throws Exception{
     80         PrintWriter writer = null;
     81         response.setCharacterEncoding("UTF-8");
     82         response.setContentType("text/html; charset=utf-8");
     83         try {
     84             writer = response.getWriter();
     85             writer.print(JsonUtil.toJson(res));
     86         } catch (Exception e) {
     87             e.printStackTrace();
     88         } finally {
     89             if (writer != null){
     90                 writer.close();
     91             }
     92         }
     93     }
     94     
     95     @Override
     96     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
     97         
     98     }
     99 
    100     @Override
    101     public void afterCompletion(HttpServletRequest request,    HttpServletResponse response, Object handler, Exception ex)    throws Exception {
    102         
    103     }
    104     
    105     /**
    106      * 
    107      * 描述:用户登录校验
    108      * @author mao2080@sina.com
    109      * @created 2017年5月9日 下午8:27:25
    110      * @since 
    111      * @param request
    112      * @throws BusinessException
    113      */
    114     private void userLoginValidate(HttpServletRequest request) throws BusinessException {
    115         //校验代码
    116     }
    117     
    118     /**
    119      * 
    120      * 描述:用户权限校验
    121      * @author mao2080@sina.com
    122      * @created 2017年5月4日 下午8:34:09
    123      * @since 
    124      * @param request HttpServletRequest
    125      * @param handler 
    126      * @return
    127      * @throws BusinessException
    128      */
    129     private void userAuthValidate(HttpServletRequest request, Object handler) throws BusinessException {
    130         AuthValidate validate = ((HandlerMethod) handler).getMethodAnnotation(AuthValidate.class);
    131         if(validate == null){
    132             throw new BusinessException("未配置自定义注解");
    133         }
    134         String funcCode = validate.value().getAuthCode();
    135         if(funcCode.equals(AuthCode.Allow.getAuthCode())){
    136             return;
    137         }
    138         String authId = validate.value().getAuthId();
    139         List<String> auths = new ArrayList<>();//模拟从缓存或者从数据库中查询出对应用户的权限
    140         if(!auths.contains(authId)){
    141             throw new BusinessException("权限不足");
    142         }
    143     }
    144 
    145 }

    5、拦截器配置

     1 package com.mao.interceptor;
     2 
     3 import org.apache.commons.logging.Log;
     4 import org.apache.commons.logging.LogFactory;
     5 import org.springframework.context.annotation.ComponentScan;
     6 import org.springframework.context.annotation.Configuration;
     7 import org.springframework.web.servlet.config.annotation.EnableWebMvc;
     8 import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
     9 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    10 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    11 
    12 /**
    13  * 
    14  * 项目名称:---
    15  * 模块名称:接入层
    16  * 功能描述:拦截器配置
    17  * 创建人: mao2080@sina.com
    18  * 创建时间:2017年5月9日 下午8:54:00
    19  * 修改人: mao2080@sina.com
    20  * 修改时间:2017年5月9日 下午8:54:00
    21  */
    22 @Configuration
    23 @ComponentScan(basePackages={"com.mao"})
    24 @EnableWebMvc
    25 public class WebConfiguration extends WebMvcConfigurerAdapter {
    26     
    27     /**日志*/
    28     private static final Log loger = LogFactory.getLog(WebConfiguration.class);
    29     
    30     /**
    31      * 
    32      * 描述:构造函数
    33      * @author mao2080@sina.com
    34      * @created 2017年5月3日 下午4:48:41
    35      * @since
    36      */
    37     public WebConfiguration() {
    38         loger.info("开启系统登录拦截");
    39     }
    40 
    41     /**
    42      * 
    43      * 描述:添加拦截器
    44      * @author mao2080@sina.com
    45      * @created 2017年4月25日 下午8:50:54
    46      * @since 
    47      * @param registry
    48      */
    49     @Override
    50     public void addInterceptors(InterceptorRegistry registry) {
    51         this.excludeUserLogin(registry.addInterceptor(new UserLoginInterceptor()));
    52     }
    53     
    54     /**
    55      * 
    56      * 描述:拦截请求
    57      * @author mao2080@sina.com
    58      * @created 2017年5月9日 下午8:55:28
    59      * @since 
    60      * @param registration
    61      */
    62     public void excludeUserLogin(InterceptorRegistration registration){
    63         registration.addPathPatterns("/userController/*");
    64     }
    65     
    66 }

    6、返回对象

      1 package com.mao.beans;
      2 
      3 import java.io.Serializable;
      4 
      5 /**
      6  * 
      7  * 项目名称:
      8  * 模块名称:
      9  * 功能描述:
     10  * 创建人: mao2080@sina.com
     11  * 创建时间:2017年5月3日 下午6:37:11
     12  * 修改人: mao2080@sina.com
     13  * 修改时间:2017年5月3日 下午6:37:11
     14  */
     15 public class ResObject implements Serializable{
     16     
     17     /**序列号*/
     18     private static final long serialVersionUID = 589903502110209046L;
     19 
     20     /**返回代码*/
     21     private int code = 200;
     22     
     23     /**返回信息*/
     24     private String desc = "Success.";
     25     
     26     /**返回数据*/
     27     private Object data;
     28 
     29     /**
     30      * 
     31      * 构建函数
     32      * @author mao2080@sina.com
     33      * @created 2017年3月24日 下午4:25:23
     34      * @since
     35      */
     36     public ResObject() {
     37         
     38     }
     39     
     40     /**
     41      * 
     42      * 描述:构造函数
     43      * @author mao2080@sina.com
     44      * @created 2017年4月18日 下午3:32:26
     45      * @since 
     46      * @param data 数据
     47      */
     48     public ResObject(Object data) {
     49         super();
     50         this.data = data;
     51     }
     52     
     53     /**
     54      * 
     55      * 构建函数
     56      * @author mao2080@sina.com
     57      * @created 2017年3月24日 下午4:25:35
     58      * @since 
     59      * @param code 返回代码
     60      * @param desc 返回信息
     61      */
     62     public ResObject(int code, String desc) {
     63         super();
     64         this.code = code;
     65         this.desc = desc;
     66     }
     67 
     68     /**
     69      * 
     70      * 构建函数
     71      * @author mao2080@sina.com
     72      * @created 2017年3月24日 下午4:25:39
     73      * @since 
     74      * @param code 返回代码
     75      * @param desc 返回信息
     76      * @param data 返回数据
     77      */
     78     public ResObject(int code, String desc, Object data) {
     79         super();
     80         this.code = code;
     81         this.desc = desc;
     82         this.data = data;
     83     }
     84 
     85     public Object getData() {
     86         return data;
     87     }
     88 
     89     public void setData(Object data) {
     90         this.data = data;
     91     }
     92 
     93     public int getCode() {
     94         return code;
     95     }
     96 
     97     public void setCode(int code) {
     98         this.code = code;
     99     }
    100 
    101     public String getDesc() {
    102         return desc;
    103     }
    104 
    105     public void setDesc(String desc) {
    106         this.desc = desc;
    107     }
    108 
    109 }
    ResObject

    7、异常类

     1 package com.mao.exception;
     2 
     3 /**
     4  * 
     5  * 项目名称:---
     6  * 模块名称:接入层
     7  * 功能描述:异常类
     8  * 创建人: mao2080@sina.com
     9  * 创建时间:2017年5月9日 下午8:22:21
    10  * 修改人: mao2080@sina.com
    11  * 修改时间:2017年5月9日 下午8:22:21
    12  */
    13 public class BusinessException extends Exception{
    14 
    15     public BusinessException() {
    16         
    17     }
    18 
    19     public BusinessException(String message) {
    20          super(message);
    21     }
    22     
    23 }
    BusinessException

    8、json工具类

      1 package com.mao.util;
      2 
      3 import com.alibaba.dubbo.common.utils.StringUtils;
      4 import com.alibaba.fastjson.JSON;
      5 import com.alibaba.fastjson.TypeReference;
      6 import com.alibaba.fastjson.parser.Feature;
      7 import com.alibaba.fastjson.serializer.SerializerFeature;
      8 import com.mao.exception.BusinessException;
      9 
     10 /**
     11  * 
     12  * 项目名称:---
     13  * 模块名称:常用工具类
     14  * 功能描述:json工具类
     15  * 创建人: mao2080@sina.com
     16  * 创建时间:2017年3月28日 上午11:56:15
     17  * 修改人: mao2080@sina.com
     18  * 修改时间:2017年3月28日 上午11:56:15
     19  */
     20 public class JsonUtil {
     21 
     22     /**
     23      * 
     24      * 描述:将对象格式化成json字符串
     25      * @author mao2080@sina.com
     26      * @created 2017年4月1日 下午4:38:18
     27      * @since 
     28      * @param object 对象
     29      * @return json字符串
     30      * @throws BusinessException 
     31      */
     32     public static String toJson(Object object) throws BusinessException {
     33         try {
     34             return JSON.toJSONString(object, new SerializerFeature[] {
     35                 SerializerFeature.WriteMapNullValue, 
     36                 SerializerFeature.DisableCircularReferenceDetect, 
     37                 SerializerFeature.WriteNonStringKeyAsString });
     38         } catch (Exception e) {
     39             throw new BusinessException();
     40         }
     41     }
     42 
     43     /**
     44      * 
     45      * 描述:将对象格式化成json字符串(PrettyFormat格式)
     46      * @author mao2080@sina.com
     47      * @created 2017年4月1日 下午4:38:18
     48      * @since 
     49      * @param object 对象
     50      * @return json字符串
     51      * @throws BusinessException 
     52      */
     53     public static String toJsonFormat(Object object) throws BusinessException {
     54         try {
     55             return JSON.toJSONString(object, new SerializerFeature[] {
     56                 SerializerFeature.WriteMapNullValue, 
     57                 SerializerFeature.PrettyFormat, 
     58                 SerializerFeature.DisableCircularReferenceDetect, 
     59                 SerializerFeature.WriteNonStringKeyAsString });
     60         } catch (Exception e) {
     61             throw new BusinessException();
     62         }
     63     }
     64 
     65     /**
     66      * 
     67      * 描述:转Map
     68      * @author mao2080@sina.com
     69      * @created 2017年4月1日 下午5:00:20
     70      * @since 
     71      * @param obj 对象
     72      * @return object
     73      * @throws BusinessException 
     74      */
     75     public static Object toJsonObject(Object obj) throws BusinessException {
     76         try {
     77             return JSON.toJSON(obj);
     78         } catch (Exception e) {
     79             throw new BusinessException();
     80         }
     81     }
     82 
     83     /**
     84      * 
     85      * 描述:将json串转为对象
     86      * @author mao2080@sina.com
     87      * @created 2017年4月1日 下午5:01:23
     88      * @since 
     89      * @param jsonString json串
     90      * @param clazz 对象
     91      * @return
     92      * @throws BusinessException 
     93      */
     94     public static <T> T fromJson(String jsonString, Class<T> clazz) throws BusinessException {
     95         try {
     96             if (StringUtils.isBlank(jsonString)) {
     97                 return null;
     98             }
     99             return (T) JSON.parseObject(jsonString, clazz);
    100         } catch (Exception e) {
    101             throw new BusinessException();
    102         }
    103     }
    104 
    105     /**
    106      * 
    107      * 描述:暂时不开通
    108      * @author mao2080@sina.com
    109      * @created 2017年4月1日 下午5:08:12
    110      * @since 
    111      * @param jsonString
    112      * @return
    113      * @throws Exception
    114      */
    115     @SuppressWarnings("unused")
    116     private static <T> T fromJson(String jsonString) throws Exception {
    117         return JSON.parseObject(jsonString, new TypeReference<T>() {
    118         }, new Feature[0]);
    119     }
    120     
    121 }
    JsonUtil
  • 相关阅读:
    IOS Array 排序方法
    一个制作Xcode5插件的模板
    UITableViewCell滑动删除及移动
    strong weak
    越狱检测/越狱检测绕过
    XML在线转化为JSON
    KissXML类库的使用方法
    iOS perform action after period of inactivity (no user interaction)
    Objective-C在ARC下结合GCD的单例模式和宏模版
    Xcode5 如何添加一个Github/Repository 并且Checkout
  • 原文地址:https://www.cnblogs.com/mao2080/p/6832609.html
Copyright © 2020-2023  润新知