API接口由于需要供第三方服务调用,所以必须暴露到外网,并提供了具体请求地址和请求参数
为了防止被第别有用心之人获取到真实请求参数后再次发起请求获取信息,需要采取很多安全机制
1.首先: 需要采用https方式对第三方提供接口,数据的加密传输会更安全,即便是被破解,也需要耗费更多时间
2.其次:需要有安全的后台验证机制【本文重点】,达到防参数篡改+防二次请求
原理:(后续补充,要参加会议)
最终实现代码(网关层验证):
1 public class APIAuth extends ZuulFilter { 2 @Override 3 public String filterType() { 4 return "pre"; 5 } 6 7 @Override 8 public int filterOrder() { 9 return 0; 10 } 11 12 @Override 13 public boolean shouldFilter() { 14 return true; 15 } 16 17 @Override 18 public Object run() { 19 RequestContext ctx = RequestContext.getCurrentContext(); 20 HttpServletRequest request = ctx.getRequest(); 21 22 String token = request.getHeader("token"); 23 String timestamp = request.getHeader("timestamp"); 24 String nonce = request.getHeader("nonce"); 25 String sign = request.getHeader("sign"); 26 27 //时间限制配置 28 int timeLimit = 30; 29 30 ctx.setSendZuulResponse(false); 31 32 //请求头参数非空验证 33 if (StringUtils.isEmpty(token) || StringUtils.isEmpty(timestamp) || StringUtils.isEmpty(nonce) || StringUtils.isEmpty(sign)) { 34 ctx.setResponseBody(JSON.toJSONString(new Result("-1", "请求头参数不正确"))); 35 return null; 36 } 37 38 //请求时间和现在时间对比验证,发起请求时间和服务器时间不能超过timeLimit秒 39 if (StringUtils.timeDiffSeconds(new Date(), timestamp) > timeLimit) { 40 ctx.setResponseBody(JSON.toJSONString(new Result("-1", "请求发起时间超过服务器限制"))); 41 return null; 42 } 43 44 //验证用户信息 45 UserInfo userInfo = UserInfoUtil.getInfoByToken(token); 46 if (userInfo == null) { 47 ctx.setResponseBody(JSON.toJSONString(new Result("-1", "错误的token信息"))); 48 return null; 49 } 50 51 //验证相同noce的请求是否已经存在,存在表示为重复请求 52 if (NoceUtil.exsit(userInfo, nonce)) { 53 ctx.setResponseBody(JSON.toJSONString(new Result("-1", "重复的请求"))); 54 return null; 55 } else { 56 //如果noce没有在缓存中,则需要加入,并设置过期时间为timeLimit秒 57 NoceUtil.addNoce(userInfo, nonce, timeLimit); 58 } 59 60 //服务器生成签名与header中签名对比 61 String serverSign = SignUtil.getSign(userinfo, token, timestamp, nonce, request); 62 if (!serverSign.equals(sign)) { 63 ctx.setResponseBody(JSON.toJSONString(new Result("-1", "错误的签名信息"))); 64 return null; 65 } 66 67 ctx.setSendZuulResponse(true); 68 return null; 69 } 70 }