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

 

转载于:https://www.cnblogs.com/mao2080/p/6832609.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值