需求:
请求加上Authorization头部,按指定格式添加校验内容。Authorization包含以下几个方面信息:
- 校验方式:固定为HMAC-SHA256
- timestamp:当前时间的13位毫秒时间戳
- signature:请求签名,按指定方式生成
Authorization格式具体为:
Authorization:HMAC-SHA256,${timestamp},${signature}
private boolean authorizationValidation(HttpServletRequest request) { CachedBodyHttpServletRequest cachedRequest = (CachedBodyHttpServletRequest) request; String authorizationHeader = request.getHeader("Authorization");try { // 解析 Authorization 值 String[] authValues = authorizationHeader.split(","); String timestamp = authValues[1]; String body = cachedRequest.getBody(); if (body == null) { body = ""; } String receivedSignature = authValues[2]; log.info("[PearlBlockController.authorizationValidation]请求的receivedSignature: {}", JsonUtils.obj2String(receivedSignature)); String path = request.getRequestURI(); String query = request.getQueryString(); if (StringUtils.isNotBlank(query)) { path += "?" + query; } // 构建参与签名的字符串 StringBuilder stringToSign = new StringBuilder(); stringToSign.append(path).append("\n"); stringToSign.append(timestamp).append("\n"); stringToSign.append(body).append("\n"); log.info("[PearlBlockController.authorizationValidation]stringToSign: {}", JsonUtils.obj2String(stringToSign)); // 使用 HMAC-SHA256 算法进行签名 SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), algorithm); Mac mac = Mac.getInstance(algorithm); mac.init(signingKey); byte[] signatureBytes = mac.doFinal(stringToSign.toString().getBytes(StandardCharsets.UTF_8)); // 对签名进行 Base64 编码 String calculatedSignature = Base64.getEncoder().encodeToString(signatureBytes);// 对比签名值 if (calculatedSignature.equals(receivedSignature)) {return true; } } catch (NoSuchAlgorithmException | InvalidKeyException e) { e.printStackTrace(); log.info(e.getMessage()); } return false; }
public class CachedBodyHttpServletRequest extends HttpServletRequestWrapper { private final byte[] cachedBody; public CachedBodyHttpServletRequest(HttpServletRequest request) throws IOException { super(request); InputStream requestInputStream = request.getInputStream(); this.cachedBody = StreamUtils.copyToByteArray(requestInputStream); } @Override public ServletInputStream getInputStream() { return new CachedBodyServletInputStream(this.cachedBody); } @Override public BufferedReader getReader() throws IOException { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.cachedBody); return new BufferedReader(new InputStreamReader(byteArrayInputStream)); } public String getBody() { return new String(cachedBody); } }
public abstract class StreamUtils { public static final int BUFFER_SIZE = 4096; public StreamUtils() { } public static byte[] copyToByteArray(InputStream in) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(4096); copy(in, out); return out.toByteArray(); } public static int copy(InputStream in, OutputStream out) throws IOException { int byteCount = 0; byte[] buffer = new byte[4096]; int bytesRead; for(boolean var4 = true; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) { out.write(buffer, 0, bytesRead); } out.flush(); return byteCount; } }