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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM