HMAC 插件实现了基于 HMAC 算法为 HTTP 请求生成不可伪造的签名,并基于签名实现身份认证。本文介绍如何使用 HMAC 插件。
HMAC 插件支持在实例、服务、路由级别的资源中开启和关闭,插件配置的生效优先级为路由 > 服务 > 实例。
HMAC 开启后,只有使用合法消费者的 AK/SK 进行签名才可以通过认证及鉴权。
AK/SK 在消费者中生成,一个消费者最多具有 1 个 AK/SK。
创建消费者。
消费者生成 AK/SK。
客户端生成签名。
服务端验证签名。
登录 API 网关控制台。
在顶部导航栏,选择目标地域。
在左侧导航栏选择 消费者管理 > 消费者列表。
在消费者页面,单击 创建消费者。
在 创建消费者 页面,完成以下配置,然后单击 确定。
配置项说明:
配置项 | 说明 | 示例值 |
---|---|---|
所属实例 | 选择消费者所属的实例。 | instance-doc |
消费者名称 | 自定义消费者名称,用于标识该消费者。 | Consumer-doc |
备注 | 可选。您可以根据业务需要选择是否编辑备注内容,例如消费者的用途,便于后期识别。 | 无 |
登录 API 网关控制台。
在顶部导航栏,选择目标地域。
在左侧导航栏选择 消费者管理 > 消费者列表。
在消费者列表中,单击目标消费者名称,进入消费者详情页面。
在认证信息区域,单击 生成 AK/SK。
在认证信息中,可以查看已生成的 AK/SK。
从原始请求中提取关键数据,得到一个用来签名的字符串 stringToSign
。
字段提取内容和规则说明:
字段 | 是否可为空 | 为空时的字段值 | 说明 |
---|---|---|---|
HTTPMethod | 否 | POST | HTTP 的方法,全部大写,比如 POST。 |
Accept | 是 | \n | 请求中的 Accept 头的值,建议显示设置 Accept Hedaer。部分 HTTP 客户端会将 Accept 默认设置为*/*导致签名失败。 |
Content-MD5 | 是 | \n | 请求存在 Body 且 Body 为非 Form 形式时计算 Content-MD5 头,可为空。
|
Content-Type | 是 | \n | 请求中的 Content-Type 头的值。 |
Date | 是 | \n | 请求中的 Date 头的值,可为空。 |
Headers | 是 | 无需加\n |
|
PathAndParameters | 是 | \n | 包含 Path,Query 和 Form 中的所有参数,具体形式如下:
|
查看原始请求。
原始请求示例如下所示:
POST/hmactest/test?param1=querystringcontent HTTP/1.1 host:example.apig.com accept:application/json; charset=utf-8 content-type:application/x-www-form-urlencoded; charset=utf-8 date:Wed, 02 May 2022 12:30:56 GMT+00:00 X-Top-Account-Id: 20*****346' X-Top-Request-Id: 02********415**********000********1b6********8*****d4 X-Top-Region: cn-north-2 content-length:33 username=test&password=test1234
从原始请求中提取关键数据。
HTTPMethod:POST Accept:application/json; charset=utf-8 Content-MD5 : Content-Type:application/x-www-form-urlencoded; charset=utf-8 Date:Wed, 02 May 2022 12:30:56 GMT+00:00 Headers: PathAndParameters:
合成签名字符串 stringToSign
。
字符串大小写敏感,字段间用\n间隔。
使用加密算法和消费者中的consumerSK
对提取的签名串stringToSign
进行加密处理得到签名sign
。
计算方法如下:
Mac hmacSha256 = Mac.getInstance("HmacSHA256"); byte[] secretBytes = consumerSK.getBytes("UTF-8"); hmacSha256.init(new SecretKeySpec(secretBytes, 0, secretBytes.length, "HmacSHA256")); byte[] result = hmacSha256.doFinal(stringToSign.getBytes("UTF-8")); String sign = Base64.encodeBase64String(result);
加密处理后得到签名sign
示例如下:
POST application/json; charset=utf-8 application/x-www-form-urlencoded; charset=utf-8 Wed, 02 May 2022 12:30:56 GMT+00:00 X-Top-Account-Id:20*****346 X-Top-Request-Id:02********415**********000********1b6********8*****d4 X-Top-Region:cn-north-2 /hmactest/test?param1=querystringcontent&username=test&password=test1234
将签名相关的所有头加入到原始 HTTP 请求中,得到最终 HTTP 请求。
POST/hmactest/test?param1=querystringcontent HTTP/1.1 host:example.apig.com accept:application/json; charset=utf-8 content-type:application/x-www-form-urlencoded; charset=utf-8 date:Wed, 02 May 2022 12:30:56 GMT+00:00 X-Top-Account-Id: 20*****346' X-Top-Request-Id: 02********415**********000********1b6********8*****d4 X-Top-Region: cn-north-2 x-apig-ca-key: 用户的AK x-apig-ca-signature-method: HmacSHA256 x-apig-ca-signature-headers: X-Top-Account-Id,X-Top-Request-Id,X-Top-Region x-apig-ca-signature: 签名计算结果 content-length:33 username=test&password=test1234
请求中新增的头内容和说明:
头内容 | 说明 |
---|---|
x-apig-ca-key | 用户的 AK |
x-apig-ca-signature-method | HmacSHA256 |
x-apig-ca-signature-headers | X-Top-Account-Id,X-Top-Request-Id,X-Top-Region |
x-apig-ca-signature | 签名计算结果 |
从接收到的请求中,提取和客户端一致的字符串 stringToSign
用来签名。
从接收到的请求中读取 consumerAK
,通过 consumerAK
查询到对应的 consumerSK
。
使用加密算法和对应的 consumerSK
,对关键数据签名串进行加密处理,得到签名。
从接收到的请求中读取客户端签名,对比服务器端签名和客户端签名的一致性。