java使用拦截器进行接口签名验证

之前有使用aop自定义注解的方式;

本篇签名验证都一样;时效;防抓包重复请求;redis验签

拦截器方法感觉解耦更强吧,结合全局异常(之前文章里有-)

1.签名验证拦截器 @Component @Slf4j public class SignAuthInterceptor implements HandlerInterceptor { private final static Long REDIS_SIGN_EXPIRE_TIME = 5 * 60 * 1000L; private final static String REDIS_KEY_PREFIX = "APPID:"; private final static String REDIS_APPSIGN_PREFIX = "APPSIGN:FILESERVER:";

@Autowired StringRedisTemplate redisTemplate;

@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String timestamp = request.getHeader("timestamp"); String appid = request.getHeader("appid"); String sign = request.getHeader("sign"); String method = request.getMethod();

if (StringUtils.isBlank(appid) || StringUtils.isBlank(sign) || StringUtils.isBlank(timestamp)) { returnJson(response, ReturnCode.INVALID_HEADER); return false; }

// 验证时间是否有效 long now = System.currentTimeMillis(); if (Math.abs(now - Long.valueOf(timestamp)) >= REDIS_SIGN_EXPIRE_TIME) { returnJson(response, ReturnCode.INVALID_TIMESTAMP); return false; }

// 验证sign MD5(appid+appkey+timestamp) 此处,省事 默认secret为Md5(appId).substring(10,14) String appSecret = ""; if (StringUtils.isBlank(appSecret)) { appSecret = DigestUtils.md5DigestAsHex(appid.getBytes(StandardCharsets.UTF_8)).substring(10, 14); } String md5Str = appid + appSecret + timestamp; log.info(md5Str); String encode = DigestUtils.md5DigestAsHex(md5Str.getBytes(StandardCharsets.UTF_8)); log.info(encode);

if (!StringUtils.equals(sign, encode) || redisTemplate.hasKey(REDIS_APPSIGN_PREFIX + sign)) { returnJson(response, ReturnCode.INVALID_SIGN); return false; }

redisTemplate.opsForValue() .set(REDIS_APPSIGN_PREFIX + sign, "1", REDIS_SIGN_EXPIRE_TIME, TimeUnit.MILLISECONDS);

return HandlerInterceptor.super.preHandle(request, response, handler); }

// 异常返回值;可以用全局异常替代,之前的文章里有 // ReturnCode 为枚举返回值 private void returnJson(HttpServletResponse response, ReturnCode returnCode){ PrintWriter writer = null; response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); try { writer = response.getWriter(); writer.print(JSON.toJSONString(ResponseWrapper.error(returnCode))); } catch (IOException e){ log.error(e.getMessage()); } finally { if(writer != null){ writer.close(); } } } }

2.添加全局配置 @Configuration public class SignAuthWebConfig implements WebMvcConfigurer {

@Autowired private SignAuthInterceptor signAuthInterceptor;

@Override public void addInterceptors(InterceptorRegistry registry) { // 添加拦截规则 registry.addInterceptor(signAuthInterceptor).addPathPatterns("/test/**"); }

// 若对参数验签,此处添加过滤器配置;防止接口层不能获取RequestBody值 // @Bean // public FilterRegistrationBean registrationBean() { // FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter()); // filterRegistrationBean.addUrlPatterns("/*"); // // return filterRegistrationBean; // }

}

经验分享 程序员 微信小程序 职场和发展