HMAC-SHA256签名

发布时间 2023-10-12 18:02:59作者: 一直深夜吃食的喵

一.需求

请求加上Authorization头部,按指定格式添加校验内容。Authorization包含以下几个方面信息:
  • 校验方式:固定为HMAC-SHA256
  • timestamp:当前时间的13位毫秒时间戳
  • 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];
      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");// 使用 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;
}
}