# 背景
在實際項目中,接口出于安全考慮,都會有驗簽的計算。目前接觸的項目來看基本都是時間戳+幹擾因子 然後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/** 不生效
目錄結構如下:

雖千萬人,吾往矣!