更新时间:2021-09-15 GMT+08:00
分享

签名流程

本节介绍签名的具体生成方法。

由于签名结果是随着时间而变化的,在如下示例中,X-Sdk-Date的样例值为20181101T081630Z,因此如果在测试代码的签名结果是否和样例结果相同时,请注意X-Sdk-Date的值不要根据当前时间来获取,而是固定为20181101T081630Z。这样才可以对比签名结果,测试完成之后,请再修改X-Sdk-Date的值,根据当前时间来获取。

在请求头列表中添加如下两个新的请求头

表1 请求头说明

请求头名称

取值描述

示例

Host

URL中的域名地址和端口信息,格式为host:port(即域名地址:端口号)

说明:

若是如下三种情况之一时,需要去掉:port,只保留host。

  • 如果URL中没有端口(会使用默认端口),此处也需要省略:port
  • 如果是http协议且指明使用80端口,此处需要省略:80
  • 如果是https协议且指明使用443端口,此处需要省略:443
  • 如URL为https://dis.${region}.myhuaweicloud.com/v2/...,则Host的值为dis.${region}.myhuaweicloud.com
  • 如URL为https://dis.${region}.myhuaweicloud.com:443/v2/...,则Host的值为dis.${region}.myhuaweicloud.com
  • 如URL为https://dis.${region}.myhuaweicloud.com:20004/v2/...,则Host的值为dis.${region}.myhuaweicloud.com:20004
  • 如URL为https://114.115.204.40/v2/...,则Host的值为114.115.204.40

X-Sdk-Date

使用当前UTC时间(北京时间-8小时)生成的字符串,格式为yyyyMMddTHHmmssZ

其中yyyy为年,MM为月,dd为天,T为固定字符,HH为时(24小时制),mm为分,ss为秒,Z为固定字符

例如在北京时间2018-11-01 16:16:30,生成的X-Sdk-Date值为20181101T081630Z

20181101T081630Z

根据样例生成的请求头列表为

Host: dis.${region}.myhuaweicloud.com
X-Sdk-Date: 20181101T081630Z

计算请求体的SHA256值

String calculateContentHash=sha256(content)

计算请求体content的sha256值获得。

如果没有请求体(即content为空),则calculateContentHash为固定值e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

根据样例:

{"stream_name":"test2","records":[{"data":"aGVsbG8gd29ybGQu","partition_id":"","explicit_hash_key":"","partition_key":"0"}]},

计算的calculateContentHash结果为:

af22378806bf4e69f5f1667877906e6ead78080cd859b4988ea6714dba6d1e02

计算CanonicalRequest

String CanonicalRequest =
        HTTPRequestMethod + '\n' +
        CanonicalURI + '\n' +
        CanonicalQueryString + '\n' +
        CanonicalHeaders + '\n' +
        SignedHeaders + '\n' +
        calculateContentHash
表2 构造CanonicalRequest所需参数说明

参数

描述

示例

HTTPRequestMethod

http请求类型

POST

CanonicalURI

URL域名端口和参数之间的资源路径。

须知:

资源路径若不以/结尾,则需要在最后补充/

  • 如URL为https://dis.${region}.myhuaweicloud.com/v2/d575b0b740e54221aeb9a165653b103d/records,则取值为/v2/d575b0b740e54221aeb9a165653b103d/records/
  • 如URL为https://dis.${region}.myhuaweicloud.com/v2/d575b0b740e54221aeb9a165653b103d/cursors/?stream-name=test2,则取值为/v2/d575b0b740e54221aeb9a165653b103d/cursors/

CanonicalQueryString

URL中的所有查询参数根据参数名称进行字典排序之后拼接的字符串,格式为

CanonicalQueryEntry0 + "&" + CanonicalQueryEntry1 + ...若没有参数,则此值为空字符串。

说明:

每个CanonicalQueryEntry的格式为UrlEncode(QueryName) + '=' + UrlEncode(QueryValue)

即请求头名称与值都进行URL编码,使用字符'='连接。

partition-id=0&stream-name=test2

CanonicalHeaders

根据请求头名称不区分大小写进行字典排序之后拼接的字符串,格式为:CanonicalHeadersEntry0 + CanonicalHeadersEntry1 + ...

说明:

每个CanonicalHeadersEntry的格式为Lowercase(HeaderName) + ':' + Trimall(HeaderValue) + '\n'(即 小写的请求头 + ':' + 将value中的多个空白字符\s+替换为单个空格 + '\n')。

host:dis.${region}.myhuaweicloud.com:20004\nx-sdk-date:20181101T081630Z\n

SignedHeaders

所有请求头名称转为小写之后进行字典排序拼接的字符串,格式为Lowercase(HeaderName0) + ';' + Lowercase(HeaderName1) + ";" + ...

说明:

先所有请求头名称转为小写,再进行字典排序,然后多个小写请求头名称之间使用;分隔

host;x-sdk-date

calculateContentHash

计算请求体的SHA256值

af22378806bf4e69f5f1667877906e6ead78080cd859b4988ea6714dba6d1e02

根据样例计算的CanonicalRequest结果为:(\n显示为换行)

POST
/v2/d575b0b740e54221aeb9a165653b103d/records/
partition-id=0&stream-name=test2
host:dis.${region}.myhuaweicloud.com
x-sdk-date:20181101T081630Z 
host;x-sdk-date
af22378806bf4e69f5f1667877906e6ead78080cd859b4988ea6714dba6d1e02

如将\n不显示为换行,则是如下格式

POST\n/v2/d575b0b740e54221aeb9a165653b103d/records/\npartition-id=0&stream-name=test2\nhost:dis.${region}.myhuaweicloud.com\nx-sdk-date:20181101T081630Z\n\nhost;x-sdk-date\naf22378806bf4e69f5f1667877906e6ead78080cd859b4988ea6714dba6d1e02

计算StringToSign

String StringToSign  =
        Algorithm + '\n' +
        RequestDate + '\n' +
        CredentialScope + '\n' +
        HashedCanonicalRequest))
表3 构造StringToSing所需参数说明

参数

描述

示例

Algorithm

加密算法,固定为SDK-HMAC-SHA256。

SDK-HMAC-SHA256

RequestDate

X-Sdk-Date的值

20181101T081630Z

CredentialScope

认证范围,格式为 date/region/service/terminationString

  • data:X-Sdk-Date的日期部分,即yyyyMMdd。
  • region:传入的region值。
  • service:服务名,请求数据接入服务固定为dis。
  • terminationString为终端标识,固定为sdk_request。

20181101/${region}/dis/sdk_request

HashedCanonicalRequest

参见计算CanonicalRequest,计算的CanonicalRequest的sha256值。

bf0eb8735b561a700b85b1142eb61df06569dffcd1088a7dda539e2ee6497809

样例结果:

StringToSign=SDK-HMAC-SHA256\n20181101T081630Z\n20181101/${region}/dis/sdk_request\n548470a57f61f5841c6869cd51164be0da033c14a874ff7a498593a4ae202b41

计算SigningKey

SigningKey是通过HmacSHA256算法计算出来的字节数组,方法如下:

        kSecret = Bytes("SDK"+sk)
        kDate = HmacSHA256(kSecret, Date)
        kRegion = HmacSHA256(kDate, Region)
        kService = HmacSHA256(kRegion, Service)
        SigningKey = HmacSHA256(kService, "sdk_request")

HmacSHA256算法以一个密钥key(格式为字节数组)和一个消息message(格式为字符串)为输入,生成一个消息摘要(格式为字节数组)作为输出。由于HmacSHA256的结果都是字节数组,为了直观表示每一步的结果,方便校验,如下示例都会将每步的范例结果Result表示为16进制字符串形式,即HexEncode(Result),注意参与计算过程的仍然是字节数组而不是它HexEncode之后的值

表4 构造SigningKey所需参数说明

参数

描述

示例(实际值经过HexEncode后的结果)

kSecret

"SDK"+sk (即sk前增加SDK三个字符)的字符串,并转为字节数组,作为初始key

53444b76524e77474d643932506c697479494f3364614473656f53396863694c39784b534b6b42694a3434

kDate

以kSecret为key,以Date(X-Sdk-Date的日期部分)为message的HmacSHA256的结果。

305758792674e5cfec8609daf3725e37367d8479ee824d2914db63004b5211b2

kRegion

以kDate为key,以Region(即入参region)为message的HmacSHA256的结果。

c56298c0270a63bb57779cdfe02d41b55393f8b61bf4c793b06866c14f9b28e7

kService

以kRegion为key,以Service(即入参service,如dis)为message的HmacSHA256的结果。

ed5246fb17c384c46000ba85a7c788e3e18c5e0323240f9bff6a1308df9179e8

SigningKey

以kService为key,以固定字符串"sdk_request"为message的HmacSHA256的结果。

1ea4929f7f18601abb9af0aaa9dc46eb0b6bda7b1de20d2a152dbe76e05dffad

由于StringToSign结果为字节数组,无法直接在文档内表示此值,故此处将样例计算出的StringToSign通过16进制字符串表示(即HexEncode(StringToSign)),是如下字符串:

1ea4929f7f18601abb9af0aaa9dc46eb0b6bda7b1de20d2a152dbe76e05dffad

这个字符串并不是StringToSign的结果,而是HexEncode(StringToSign)的结果,此处这样表示只是为了方便使用者核对结果是否正确。在下一步计算Signature时,需要传入的还是StringToSign

由于SigningKey只与sk, date, region, service有关。当这四个参数不变时,SigningKey的值都是固定的。故为了提升性能,可以把SigningKey的结果缓存起来,重复使用。

计算Signature

String Signature = HexEncode(HmacSHA256(SigningKey, StringToSign))

构造Signature所需参数说明:

SigningKey为key,以StringToSign为message的HmacSHA256的结果(字节数组),并转换为16进制字符串。

根据样例计算的Signature结果为:

8df520f285a18b7b101fc0d6507de03c4078460c65baa289ffa49ca718e9190b

生成签名信息到Request中

在请求头中在增加如下值,即可完成签名。

Authorization: SDK-HMAC-SHA256 Credential=ak/CredentialScope, SignedHeaders=SignedHeaders, Signature=signature

  • ak,即用户ak。

    样例:DJZN5UEQSODCWJ7NGOMC

  • CredentialScope,即计算StringToSign中用到的认证范围。

    样例:20181101/${region}/dis/sdk_request

  • SignedHeaders,即计算CanonicalRequest中用到的SignedHeaders。

    样例:host;x-sdk-date

  • signature,即计算Signature中得出的signature。

    样例:8df520f285a18b7b101fc0d6507de03c4078460c65baa289ffa49ca718e9190b

    根据样例计算的签名请求头为

    Authorization: SDK-HMAC-SHA256 Credential=DJZN5UEQSODCWJ7NGOMC/20181101/${region}/dis/sdk_request, SignedHeaders=host;x-sdk-date, Signature=8df520f285a18b7b101fc0d6507de03c4078460c65baa289ffa49ca718e9190b

问题分析

  • 如果签名正确,但是AK或者ProjectId不存在,服务端返回:
    441 : Invalid AccessKey header. [Invaild ak.]

    解决方法:

    参见AK/SK认证的方法,确保AK正确。

    参见获取项目ID的方法,确保ProjectId正确。

  • 如果签名逻辑或者Sk错误,则服务端返回:
    441 : Invalid authorization request.

    解决方法:

    使用示例参数验证签名流程,与示例结果比对,确保签名过程无误。

  • 如果Region错误(例如使用华北区1的${region},却请求华南区的DIS地址),则服务端返回:
    441 : Invalid Region header. [${region}]

    解决方法:

    参见获取项目ID的方法,确保Region与DIS地址一一对应。

  • 如果X-Sdk-Date的时间落后标准时间15分钟以上,则服务端会返回:
    441 : Invalid X-Sdk-Date header

    解决方法:

    调整客户端时间为对应时区的标准时间即可。

分享:

    相关文档

    相关产品

关闭导读