# 背景
在實際項目中,接口出於安全考慮,都會有驗簽的計算。目前接觸的項目來看基本都是時間戳+干擾因子 然后md5計算的方式。現在學習,寫一個簡單demo,
其實如果不引入攔截器的話,驗簽計算全部在controller層實現也是可以的,但每個請求都需要去做一次計算,這種把公共功能的抽離,針對於所有請求前的判斷,個人感覺有點切面的意思;
# DEMO
核心點:
1. controller層還是和原來的一模一樣,不做修改
2. 創建一個ApiSignInterceptor 類 ,實現HandlerInterceptor 接口,完成 驗簽計算的核心代碼;
3. 創建一個WebConfig類,繼承WebMvcConfigurationSupport類,引入步驟2中創建的攔截器;
前言:
jdk8+spring boot2.0 版本 如果低版本些許不一致
show CODE
controller層:
@RestController public class PeopleController { @GetMapping(value = "/1/people/{people_id}") public String getPeopleInfo(@PathVariable(value = "people_id", required = true) String peopleId) { return "hello world, this is people info of " + peopleId; } @GetMapping(value = "/2/people/{people_id}") public String getPeopleInfoV2(@PathVariable(value = "people_id", required = true) String peopleId) { return "hello THIS is v2 world, this is people info V2 of " + peopleId; } }
沒有任何變化,簡單demo例子
攔截器,ApiSignInterceptor :
public class ApiSignInterceptor implements HandlerInterceptor { private final static String SEPERATOR = "_"; private final static String SECRET = "jwentest"; private final static String NO_PERMISSION_ERROR_MESSAGE = "Api Token Error, You have no permission to access this api"; // md5計算 private String md5Hex(String data) { return DigestUtils.md5Hex(data).toLowerCase(); } private String getSign(String t) { return md5Hex(t + SEPERATOR + SECRET); } // sign計算,t為時間戳,sign為md5(t+"_"+"jwentest") @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { try { String t = request.getParameter("t"); String sign = request.getParameter("sign"); if (t.isEmpty() || sign.isEmpty()) { response.sendError(403, NO_PERMISSION_ERROR_MESSAGE); return false; } String expectedSign = getSign(t); if (!expectedSign.equals(sign)) { response.sendError(403, NO_PERMISSION_ERROR_MESSAGE); return false; } } catch (Throwable t) { response.sendError(403, NO_PERMISSION_ERROR_MESSAGE); return false; } return true; } }
其中HandlerInterceptor 接口定義了三個方法,第一次看到我有點懵逼了,為啥接口定義的方法里面會有方法體呢,為什么可以不實現所有的方法了的,原因是JDK8中可以這樣寫了:
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { }
本次我們使用到的是preHandle方法,三個方法的執行順序如下:
preHandler -> Controller -> postHandler -> model渲染-> afterCompletion
因此可以在進入controller層之前攔截判斷是否符合我們的安全要求;
使用,WebConfig 類:
@Configuration public class WebConfig extends WebMvcConfigurationSupport { @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new ApiSignInterceptor()).addPathPatterns("/1/people/**").excludePathPatterns("/2/people/**"); super.addInterceptors(registry); } }
這里是在項目引入攔截器,
@Configuration ,config形式加載在容器中
其中addPathPatterns 和 excludePathPatterns 方法,從方法名就可以看出來,是針對攔截器的范圍控制,上面的代碼就是針對/1/people/** 生效,對/2/people/** 不生效
目錄結構如下: