推送AKSK验证
功能介绍
当开启推送AK/SK验证,并设置推送AK和SK后,平台将在HTTP推送状态报告时增加签名时间戳(X-Sdk-Date)和用于消息鉴权的哈希码(Authorization)。
注意事项
修改AK/SK后生效时间大约5分钟,期间可能会导致状态报告/上行短信推送验证失败。可采用双AK/SK的方式,即同时支持两个AK/SK生效。通过Authorization请求头中的Access字段,可以判断当前请求所使用的有效SK(Secret Key)。
校验方法
需额外引入maven依赖,示例代码中使用了该依赖实现AK/SK签名。
以下代码示例中的version值,请根据实际的SDK版本号进行替换。具体的SDK版本号请参见SDK开发中心。
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<!-- 使用时替换为实际路径-->
<systemPath>${project.basedir}/libs/java-sdk-core-XXX.jar</systemPath>
<groupId>com.huawei.apigateway</groupId>
<artifactId>java-sdk-core</artifactId>
<version>SDK版本号</version>
<scope>system</scope>
</dependency>
校验Authorization的java示例如下:
@RestController
public class StatusReportController {
private static final Pattern AUTHORIZATION_PATTERN_SHA256 = Pattern.compile(
"SDK-HMAC-SHA256\\s+Access=([^,]+),\\s?SignedHeaders=([^,]+),\\s?Signature=(\\w+)");
private static Map<String, String> secretMap = new HashMap<>();
static {
secretMap.put("exampleAk", "exampleSk*1231d881wd");
}
static class Response {
int returnCode;
String returnCodeDesc;
Response(int returnCode, String returnCodeDesc) {
this.returnCode = returnCode;
this.returnCodeDesc = returnCodeDesc;
}
public int getReturnCode() {
return returnCode;
}
public String getReturnCodeDesc() {
return returnCodeDesc;
}
}
@PostMapping("/status")
public ResponseEntity<Response> smsHwStatusReport(HttpServletRequest request) {
if (!doAuth(request)) {
// 验证失败,返回状态码 401
return ResponseEntity
.status(HttpStatus.UNAUTHORIZED) // 设置 HTTP 状态为 401
.contentType(MediaType.APPLICATION_JSON)
.body(new Response(401, "Unauthorized"));
}
// 正常处理状态报告
return ResponseEntity
.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body(new Response(0, "Success"));
}
public boolean doAuth(HttpServletRequest request) {
try {
if (StringUtils.isEmpty(request.getHeader("Authorization"))) {
// 不包含 Authorization header
return false;
}
Matcher match = AUTHORIZATION_PATTERN_SHA256.matcher(request.getHeader("Authorization"));
if (!match.find()) {
// Authorization 格式错误
return false;
}
String ak = match.group(1); // 获取access key
String body = new String(IOUtils.toByteArray(request.getInputStream()), StandardCharsets.UTF_8); //
// 获取消息体字符串
Request r = new Request();
r.setAppKey(ak);
r.setSecret(secretMap.get(ak)); // 获取secret key
r.setUrl(request.getRequestURI()); // 获取消息路径
r.setBody(body);
r.setMethod(request.getMethod());
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
r.addHeader(headerName.toLowerCase(Locale.ROOT), request.getHeader(headerName));
}
Signer signer = new Signer();
return signer.verify(r);
} catch (Exception e) {
return false;
}
}
}