更新时间:2024-12-20 GMT+08:00
分享

推送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;
        }
    }
}

相关文档