生成认证字符串

相关参考 Reference

  • 文档有奖反馈活动
  • 文档有奖反馈2
  • 功能发布记录
  • 捉虫活动获奖名单
  • 鉴权认证机制
    • 常见签名认证错误排查
    • 简介
    • 在URL中包含认证字符串
    • 在Header中包含认证字符串
    • 签名流程
    • Sample-Code
    • 生成V2认证字符串
    • 错误码
    • 生成认证字符串
  • SDK入门指南
    • Python-SDK帮助指南
    • PHP-SDK入门指南
    • Java-SDK入门指南
  • 区域选择说明
    • 区域
    • 可用区
  • API SDK
    • Java-SDK
  • 证书管理
    • 多用户访问控制
    • 管理证书
    • 格式转换
    • 简介
    • Python-SDK
    • GO-SDK
    • 上传证书
    • 证书和私钥
    • API参考
    • 常见问题
    • 第三方机构创建证书
    • 证书替换
    • JAVA-SDK
  • 企业组织
    • 退出组织
    • 账户联合认证(SSO)
    • 权限策略管理
    • 子账户管理
    • 产品介绍
    • 财务管理
    • 常见问题
    • 企业组织vs多用户访问控制
    • 权限评估逻辑
    • 创建企业组织
    • 系统限制
    • 组织单元
    • API参考
      • 通用说明
      • 企业组织管理接口
      • 邀请管理接口
      • 策略管理接口
      • 简介
      • 单元管理接口
      • 账户管理接口
      • 数据类型
  • API Key
    • 操作手册
    • 简介
    • API参考
  • 获取AKSK
    • 简介
    • 如何获取AKSK
  • 术语表
    • B
    • Z
    • F
    • G
    • C
    • H
    • P
    • L
    • T
    • M
    • I
    • Q
    • N
    • V
    • J
    • R
    • K
    • S
    • O
    • W
    • D
    • X
    • A
    • Y
    • E
所有文档
menu
没有找到结果,请重新输入

相关参考 Reference

  • 文档有奖反馈活动
  • 文档有奖反馈2
  • 功能发布记录
  • 捉虫活动获奖名单
  • 鉴权认证机制
    • 常见签名认证错误排查
    • 简介
    • 在URL中包含认证字符串
    • 在Header中包含认证字符串
    • 签名流程
    • Sample-Code
    • 生成V2认证字符串
    • 错误码
    • 生成认证字符串
  • SDK入门指南
    • Python-SDK帮助指南
    • PHP-SDK入门指南
    • Java-SDK入门指南
  • 区域选择说明
    • 区域
    • 可用区
  • API SDK
    • Java-SDK
  • 证书管理
    • 多用户访问控制
    • 管理证书
    • 格式转换
    • 简介
    • Python-SDK
    • GO-SDK
    • 上传证书
    • 证书和私钥
    • API参考
    • 常见问题
    • 第三方机构创建证书
    • 证书替换
    • JAVA-SDK
  • 企业组织
    • 退出组织
    • 账户联合认证(SSO)
    • 权限策略管理
    • 子账户管理
    • 产品介绍
    • 财务管理
    • 常见问题
    • 企业组织vs多用户访问控制
    • 权限评估逻辑
    • 创建企业组织
    • 系统限制
    • 组织单元
    • API参考
      • 通用说明
      • 企业组织管理接口
      • 邀请管理接口
      • 策略管理接口
      • 简介
      • 单元管理接口
      • 账户管理接口
      • 数据类型
  • API Key
    • 操作手册
    • 简介
    • API参考
  • 获取AKSK
    • 简介
    • 如何获取AKSK
  • 术语表
    • B
    • Z
    • F
    • G
    • C
    • H
    • P
    • L
    • T
    • M
    • I
    • Q
    • N
    • V
    • J
    • R
    • K
    • S
    • O
    • W
    • D
    • X
    • A
    • Y
    • E
  • 文档中心
  • arrow
  • 相关参考Reference
  • arrow
  • 鉴权认证机制
  • arrow
  • 生成认证字符串
本页目录
  • 概述
  • 生成公式
  • 生成方式
  • 方式一:线下编程生成
  • 方式二:在线签名工具生成
  • 方式三:Postman脚本直接生成
  • 编码生成步骤
  • 任务一:创建前缀字符串(authStringPrefix)
  • 任务二:创建规范请求(canonicalRequest),确定签名头域(signedHeaders)
  • 1. HTTP Method
  • 2. CanonicalURI
  • 3. CanonicalQueryString
  • 4. CanonicalHeaders
  • 任务三:生成派生密钥(signingKey)
  • 任务四:生成签名摘要及认证字符串(authorization)
  • 认证字符串示例
  • 相关函数说明

生成认证字符串

更新时间:2025-08-22

概述

当您将HTTP请求发送到百度智能云时,您需要对您的请求进行签名计算并生成认证字符串,以便百度智能云可以识别您的身份。您将使用百度智能云的访问密钥来进行签名计算,该访问密钥包含访问密钥ID(Access Key Id, 后文简称AK)和秘密访问密钥(Secret Access Key, 后文简称SK).

生成公式

认证字符串的生成公式如下:

bce-auth-v1/{accessKeyId}/{timestamp}/{expirationPeriodInSeconds }/{signedHeaders}/{signature}

主要包含了3部分,即前缀字符串(authStringPrefix)、签名头域(signedHeaders)和签名摘要(signature),其中:

前缀字符串:bce-auth-v1/{accessKeyId}/{timestamp}/{expirationPeriodInSeconds },都是可获得的参数;

签名头域:即签名算法中涉及到的HTTP头域列表,将在下文中详细描述

签名摘要:为计算所得,将在下文中详细描述

生成方式

您可以使用线下编程、在线签名工具或是Postman脚本的方式生成v1版本的认证字符串。

方式一:线下编程生成

您也可以通过下面的文字了解认证字符串的具体生成过程,然后自己编写代码生成相应的认证字符串。

方式二:在线签名工具生成

百度智能云提供了在线生成签名工具,用户仅需填写必要请求信息、访问密钥(包含访问密钥ID(AK)和秘密访问密钥(SK)),可快速生成认证字符串。

方式三:Postman脚本直接生成

百度智能云同时提供了基于Postman脚本的方式,用户仅需按照手册中的步骤,进行简单的配置,就能自动计算百度智能云的签名和认证字符串。

编码生成步骤

使用编码方式生成最终的认证字符串,您需要完成如下4个子任务:

  • 任务一:创建前缀字符串(authStringPrefix)
  • 任务二:创建规范请求(canonicalRequest),确定签名头域(signedHeaders)
  • 任务三:生成派生签名密钥(signingKey)
  • 任务四:生成签名摘要(signature),并拼接最终的认证字符串(authorization)

从认证字符串格式可以看出,除了参数签名摘要(signature)外,其他参数都是已知或可设置的。 下面详细介绍签名的生成过程,进而得出认证字符串。

签名的计算公式为signature = HMAC-SHA256-HEX(SigningKey,CanonicalRequest),从公式可以看出,想要获得签名需要得到SigningKey和CanonicalRequest两个参数,首先介绍如何获取这两个参数。

任务一:创建前缀字符串(authStringPrefix)

创建前缀字符串,即将已知参数拼接为如下形式:

bce-auth-v1/{accessKeyId}/{timestamp}/{expirationPeriodInSeconds}

其中:

  • accessKeyId: Access Key ID,请参看获取AK/SK来获取。
  • timestamp:生成签名的UTC时间,格式为yyyy-mm-ddThh:mm:ssZ,例如:2015-04-27T08:23:49Z,请注意请求发送时间不能晚于生成签名时间太多,否则请求到达百度智能云时可能已经超过签名的有效期限。
  • expirationPeriodInSeconds:签名有效期限,从timestamp所指定的时间开始计算,单位为秒。

上述参数拼接:bce-auth-v1/{accessKeyId}/{timestamp}/{expirationPeriodInSeconds},组成了认证字符串前缀authStringPrefix。

任务二:创建规范请求(canonicalRequest),确定签名头域(signedHeaders)

CanonicalRequest的计算公式为: CanonicalRequest = HTTP Method + "\n" + CanonicalURI + "\n" + CanonicalQueryString + "\n" + CanonicalHeaders。

从公式可以看出CanonicalRequest由HTTP Method、CanonicalURI、CanonicalQueryString和CanonicalHeaders四部分组成,它们的具体含义及获取方式如下。

1. HTTP Method

指HTTP协议中定义的GET、PUT、POST等请求方法,必须使用全大写的形式。百度智能云API所涉及的HTTP Method有如下五种。

Plain Text
1 GET
2 POST
3 PUT
4 DELETE
5 HEAD

2. CanonicalURI

CanonicalURI是对URL中的绝对路径进行编码后的结果,即CanonicalURI = UriEncodeExceptSlash(Path)。要求绝对路径Path必须以“/”开头,不以“/”开头的需要补充上,空路径为“/”。函数UriEncodeExceptSlash的具体含义及功能请参考相关函数。

  • 示例:

若URL为https://bos.cn-n1.baidubce.com/example/测试,则其URL Path为/example/测试,将之规范化得到CanonicalURI =UriEncodeExceptSlash(/example/测试)= /example/%E6%B5%8B%E8%AF%95。

3. CanonicalQueryString

CanonicalQueryString是对于URL中的Query String(Query String即URL中“?”后面的“key1 = value1 & key2 = value2 ”字符串)进行编码后的结果。

编码步骤如下:

  1. 提取URL中的Query String项,即URL中“?”后面的“key1 = value1 & key2 = value2 ”字符串。
  2. 将Query String根据&分隔符拆开成若干项,每一项是key=value或者只有key的形式。
  3. 对拆开后的每一项进行编码处理,分以下三种情况。

    • 当该项的key是authorization时,直接忽略该项。
    • 当该项只有key时,转换公式为UriEncode(key) + "="的形式。
    • 当该项是key=value的形式时,转换公式为 UriEncode(key) + "=" + UriEncode(value) 的形式。这里value可以是空字符串。
  4. 将每一项转换后的字符串按照字典顺序(ASCII码由小到大)排序,并使用& 符号连接起来,生成相应的CanonicalQueryString。

编码示例:

获取URL为https://bos.cn-n1.baidubce.com/example?text&text1=测试&text10=test的CanonicalQueryString。

  1. 提取URL中的Query String,得到 text&text1=测试&text10=test。
  2. 根据&对Query String进行拆分,得到text 、text1=测试 、 text10=test三项。
  3. 对拆分的每一项进行编码。

    • 对text项进行编码:UriEncode("text") + "=",得到"text="
    • 对text1=测试项进行编码:UriEncode("text1") + "=" + UriEncode("测试"),得到"text1=%E6%B5%8B%E8%AF%95"
    • 对text10=test项进行编码:UriEncode("text10") + "=" + UriEncode("test"),得到"text10=test"
  4. 对上面三项编码后的字符串进行(按照ASCII码由小到大)排序,得到结果是text10=test 、text1=%E6%B5%8B%E8%AF%95 、text= ,然后用&连接起来,得到CanonicalQueryString为text10=test&text1=%E6%B5%8B%E8%AF%95&text=。

说明:

  1. 函数UriEncode的含义及功能请参考相关解释 。
  2. 示例中展示了如何处理只有key的项,非英文的value,以及数字和=进行排序。在实际的BCE API中,因为参数起名是规范的,基本不会遇到这样的排序。正常的排序结果和只按照key进行排序是完全一致的。算法中有这个约束主要是出于定义严密性的考虑。

4. CanonicalHeaders

CanonicalHeaders是对HTTP请求中的Header部分进行选择性编码的结果。

在这个步骤中,可根据Header部分确定签名头域(signedHeaders)。签名头域是指签名算法中涉及到的HTTP头域列表。HTTP头域名字一律要求小写且头域名字之间用分号(;)分隔,如host;range;x-bce-date。列表按照字典序排列。当它为空时表示取默认值,详情可见下文的编码步骤。

编码步骤如下:

  1. 选择编码的Header。 您可以自行决定哪些Header需要编码。百度智能云API的唯一要求是Host域必须被编码。大多数情况下,我们推荐您对以下Header进行编码:

    • Host
    • Content-Length
    • Content-Type
    • Content-MD5
    • 所有以 x-bce- 开头的Header

    说明

    1. 如果上述Header没有全部出现在您的HTTP请求里面,那么没有出现的部分无需进行编码。如果发送的请求里包含以上header,出现的header必须签名。
    2. 如果您使用上述推荐范围的Header进行编码,那么认证字符串中的 {signedHeaders} 可以直接留空,无需填写。如果您传入了signedHeaders,此时会根据signedHeaders内容进行签名。
    3. 您也可以自己选择想要编码的Header。如果您选择了不在推荐范围内的Header进行编码,或者您的HTTP请求包含了推荐范围内的Header但是您选择不对它进行编码,那么您必须在认证字符串中填写 {signedHeaders} 。填写方法为,把所有在这一阶段进行了编码的Header名字转换成全小写之后按照字典序排列,然后用分号(;)连接。
    4. 选择哪些Header进行编码不会影响API的功能,但是如果选择太少则可能遭到中间人攻击,百度智能云要求至少要包含Host域。
  2. 对Header进行编码获取CanonicalHeaders,编码步骤如下。

    1. 将Header的名字变成全小写,注意仅改名字。
    2. 将Header的值去掉开头和结尾的空白字符。
    3. 经过上一步之后值为空字符串的Header忽略,其余的转换为 UriEncode(name) + ":" + UriEncode(value) 的形式。
    4. 把上面转换后的所有字符串按照字典序进行排序。
    5. 将排序后的字符串按顺序用\n符号连接起来得到最终的CanonicalHeaders。

说明:
1.UriEncode的含义及功能请参考相关函数说明。

  1. 很多发送HTTP请求的第三方库,会添加或者删除你指定的header(例如:某些库会删除content-length:0这个header),如果签名错误,请检查您真实发出的http请求的header,看看是否与签名时的header一样。

编码示例1:
该示例演示使用百度智能云推荐范围之外的Header进行编码,此时signedHeaders不能为空(默认值)。在下面的示例中选择对 Date 进行编码,忽略 x-bce-date。

如下是发送请求的Header:

Plain Text
1Host: bj.bcebos.com 
2Date: Mon, 27 Apr 2015 16:23:49 +0800  
3Content-Type: text/plain 
4Content-Length: 8
5Content-Md5: NFzcPqhviddjRNnSOGo4rw==
6x-bce-date: 2015-04-27T08:23:49Z
  1. 选择需要编码的Header,然后把所有名字都改为小写。
Plain Text
1host: bj.bcebos.com
2date: Mon, 27 Apr 2015 16:23:49 +0800
3content-type: text/plain
4content-length: 8
5content-md5: NFzcPqhviddjRNnSOGo4rw==
  1. 将Header的值去掉开头和结尾的空白字符。
Plain Text
1host:bj.bcebos.com
2date:Mon, 27 Apr 2015 16:23:49 +0800
3content-type:text/plain
4content-length:8
5content-md5:NFzcPqhviddjRNnSOGo4rw==
  1. 对每个Header进行UriEncode转换。
Plain Text
1host:bj.bcebos.com
2date:Mon%2C%2027%20Apr%202015%2016%3A23%3A49%20%2B0800
3content-type:text%2Fplain
4content-length:8
5content-md5:NFzcPqhviddjRNnSOGo4rw%3D%3D?
  1. 将步骤3中转换后的所有字符串按照字典序进行排序。
Plain Text
1content-length:8
2content-md5:NFzcPqhviddjRNnSOGo4rw%3D%3D?
3content-type:text%2Fplain
4date:Mon%2C%2027%20Apr%202015%2016%3A23%3A49%20%2B0800
5host:bj.bcebos.com
  1. 将排序后的字符串按顺序用\n符号连接起来得到最终结果。
Plain Text
1content-length:8
2content-md5:NFzcPqhviddjRNnSOGo4rw%3D%3D?
3content-type:text%2Fplain
4date:Mon%2C%2027%20Apr%202015%2016%3A23%3A49%20%2B0800
5host:bj.bcebos.com

同时获得认证字符串的signedHeaders内容应该是content-length;content-md5;content-type;date;host。

编码示例2:

该示例演示了CanonicalHeaders的排序和signedHeaders排序不一致的情况。因为BCE API存在允许用户自定义Header的情况,所以这里需要特别注意。

如在BOS的PutObject中允许用户上传自定义meta,为了简明介绍,我们省略大部分Header,假设要编码的Headers如下:

Plain Text
1Host: bj.bcebos.com
2x-bce-meta-data: my meta data
3x-bce-meta-data-tag: description

按照上面的编码步骤,最终得到的CanonicalHeaders是:

Plain Text
1host:bj.bcebos.com
2x-bce-meta-data-tag:description
3x-bce-meta-data:my%20meta%20data

此时获取的signedHeaders是host;x-bce-meta-data;x-bce-meta-data-tag。

可以看出CanonicalHeaders和signedHeaders的排序不一样,这是因为signedHeaders是根据Header的name进行排序的, x-bce-meta-data 放在 x-bce-meta-data-tag 之前。但是在CanonicalHeaders中是按照name和value合成的整个字符串进行排序的,因为在name和value之间还有一个冒号(:),而冒号的ASCII码值要大于连字号(-)的ASCII码值,因此x-bce-meta-data反而放在了x-bce-meta-data-tag之后。

任务三:生成派生密钥(signingKey)

SigningKey = HMAC-SHA256-HEX(sk, authStringPrefix),其中:

  • HMAC-SHA256-HEX是HMAC SHA256算法函数,具体功能及描述参见相关函数说明。
  • sk为用户的Secret Access Key,可以通过在控制台中进行查询,关于SK的获取方法,请参看获取AK/SK。
  • authStringPrefix代表认证字符串的前缀部分,即:bce-auth-v1/{accessKeyId}/{timestamp}/{expirationPeriodInSeconds}。

任务四:生成签名摘要及认证字符串(authorization)

通过上面的计算得到的SigningKey和CanonicalRequest按照下面公式可以得到签名。
Signature = HMAC-SHA256-HEX(SigningKey, CanonicalRequest)
其中:

  • HMAC-SHA256-HEX是HMAC SHA256算法函数,具体功能及描述参见相关函数说明。

最后由公式bce-auth-v1/{accessKeyId}/{timestamp}/{expirationPeriodInSeconds }/{signedHeaders}/{signature}得到认证字符串。

认证字符串示例

上面介绍如何生成字符串后,在下面示例中详细的演示生成的每一个步骤。示例中假设用户向北京的BOS集群使用UploadPart接口上传一个文件的最后一个Part,内容为Example。 用户信息如下

Plain Text
1Bucket name:test
2Object key:myfolder/readme.txt
3uploadId:a44cc9bab11cbd156984767aad637851
4partNumber:9
5Access Key ID:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
6Secret Access Key:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
7时间:北京时间2015年4月27日16点23分49秒(转换为UTC时间是2015年4月27日8点23分49秒)

则用户发送的HTTP请求为:

XML
1PUT /v1/test/myfolder/readme.txt?partNumber=9&uploadId=a44cc9bab11cbd156984767aad637851 HTTP/1.1
2Host: bj.bcebos.com
3Date: Mon, 27 Apr 2015 16:23:49 +0800
4Content-Type: text/plain
5Content-Length: 8
6Content-Md5: NFzcPqhviddjRNnSOGo4rw==
7x-bce-date: 2015-04-27T08:23:49Z
8
9Example
  1. 生成CanonicalRequest。

    CanonicalRequest由 HTTP Method 、 CanonicalURI 、CanonicalQueryString 、CanonicalHeaders四部分构成。

    Plain Text
    1HTTP Method ="PUT" 
    2CanonicalURI= UriEncodeExceptSlash(/v1/test/myfolder/readme.txt)="/v1/test/myfolder/readme.txt"
    3CanonicalQueryString="partNumber=9&uploadId=a44cc9bab11cbd156984767aad637851"
    4CanonicalHeaders="content-length:8
    5 content-md5:NFzcPqhviddjRNnSOGo4rw%3D%3D
    6 content-type:text%2Fplain
    7 host:bj.bcebos.com
    8 x-bce-date:2015-04-27T08%3A23%3A49Z"

    最后通过公式CanonicalRequest = HTTP Method + "\n" + CanonicalURI + "\n" + CanonicalQueryString + "\n" + CanonicalHeaders得到CanonicalRequest。

    Plain Text
    1PUT
    2/v1/test/myfolder/readme.txt
    3partNumber=9&uploadId=a44cc9bab11cbd156984767aad637851
    4content-length:8
    5content-md5:NFzcPqhviddjRNnSOGo4rw%3D%3D
    6content-type:text%2Fplain
    7host:bj.bcebos.com
    8x-bce-date:2015-04-27T08%3A23%3A49Z
  2. 生成SigningKey

    通过公式SigningKey = HMAC-SHA256-HEX(sk, authStringPrefix)计算SigningKey。
    SigningKey= HMAC-SHA256-HEX("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "bce-auth-v1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/2015-04-27T08:23:49Z/1800")=1d5ce5f464064cbee060330d973218821825ac6952368a482a592e6615aef479

  3. 生成Signature

    由公式Signature = HMAC-SHA256-HEX(SigningKey, CanonicalRequest)得到 Signature= d74a04362e6a848f5b39b15421cb449427f419c95a480fd6b8cf9fc783e2999e

  4. 生成认证字符串

    Authorization = bce-auth-v1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/2015-04-27T08:23:49Z/1800//d74a04362e6a848f5b39b15421cb449427f419c95a480fd6b8cf9fc783e2999e

  5. 用户最终发送的HTTP请求中包含认证信息

    Plain Text
    1PUT /v1/test/myfolder/readme.txt?partNumber=9&uploadId=a44cc9bab11cbd156984767aad637851 HTTP/1.1
    2Authorization:bce-auth-v1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/2015-04-27T08:23:49Z/1800//d74a04362e6a848f5b39b15421cb449427f419c95a480fd6b8cf9fc783e2999e
    3Host: bj.bcebos.com
    4Date: Mon, 27 Apr 2015 16:23:49 +0800
    5Content-Type: text/plain
    6Content-Length: 8
    7Content-Md5: NFzcPqhviddjRNnSOGo4rw==
    8x-bce-date: 2015-04-27T08:23:49Z
    9
    10
    11Example

注意:

超时时间1800与签名结果之间为两个”/”,含义是使用默认签名方式,signedHeaders内容留空。

相关函数说明

函数名 功能描述
HMAC-SHA256-HEX() 调用HMAC SHA256算法,根据开发者提供的密钥(key)和密文(message)输出密文摘要,并把结果转换为小写形式的十六进制字符串。
Lowercase() 将字符串全部变成小写。
Trim() 去掉字符串开头和结尾的空白字符。
UriEncode() RFC 3986规定,"URI非保留字符"包括以下字符:字母(A-Z,a-z)、数字(0-9)、连字号(-)、点号(.)、下划线(_)、波浪线(~),算法实现如下:
1. 将字符串转换成UTF-8编码的字节流
2. 保留所有“URI非保留字符”原样不变
3. 对其余字节做一次RFC 3986中规定的百分号编码(Percent-encoding),即一个“%”后面跟着两个表示该字节值的十六进制字母,字母一律采用大写形式。
UriEncodeExceptSlash() 与UriEncode() 类似,区别是斜杠(/)不做编码。一个简单的实现方式是先调用UriEncode(),然后把结果中所有的%2F都替换为/

UriEncode()函数参考代码如下:

Plain Text
1public static String uri-encode(CharSequence input, boolean encodeSlash) {
2    StringBuilder result = new StringBuilder();
3        for (int i = 0; i < input.length(); i++) {
4            char ch = input.charAt(i);
5            if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '-' || ch == '~' || ch == '.') {
6                result.append(ch);
7            } else if (ch == '/') {
8                result.append(encodeSlash ? "%2F" : ch);
9            } else {
10                result.append(toHexUTF8(ch));
11            }
12        }
13          return result.toString();
14}

上一篇
错误码
下一篇
SDK入门指南