你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

通过共享密钥进行授权

对存储服务提出的每个请求都必须获得授权,除非该请求针对的 Blob 或容器资源已可用于公共或签名访问。 授权请求的一个选项是使用共享密钥,如本文所述。

提示

Azure 存储支持与 Azure Active Directory 集成,以精细控制对存储资源的访问。 Azure AD Blob 和队列服务支持集成。 由于Azure AD标识管理,因此可以授权访问存储资源,而无需将帐户访问密钥存储在应用程序中,就像使用共享密钥一样。 有关详细信息,请参阅使用Azure Active Directory。

Blob、队列、表和文件服务支持以下适用于 Blob、队列和表服务 (版本 2009-09-19 及更高版本的共享密钥授权方案) 以及适用于文件服务) 的 2014-02-14 及更高版本 (:

  • 用于 Blob、队列和文件服务的共享密钥。 使用共享密钥授权方案针对 Blob、队列和文件服务进行请求。 版本 2009-09-19 及更高版本中的共享密钥授权支持增强签名字符串以增强安全性,并且要求更新服务以使用此增强签名进行授权。

  • 用于表服务的共享密钥。 使用共享密钥授权方案,使用共享密钥授权方案对表服务REST API。 版本 2009-09-19 及更高版本中表服务的共享密钥授权使用与以前版本的表服务相同的签名字符串。

  • 共享密钥 Lite。 使用共享密钥 Lite 授权方案针对 Blob、队列、表和文件服务进行请求。

    对于 Blob 和队列服务的版本 2009-09-19 及更高版本,共享密钥 Lite 授权支持使用签名字符串,该字符串与以前版本的 Blob 和队列服务中对共享密钥的支持相同。 因此,可以使用共享密钥 Lite 请求 Blob 和队列服务,而无需更新签名字符串。

授权请求需要两个标头:或 Date x-ms-date 标头和 Authorization 标头。 以下几节介绍如何构造这些标头。

重要

Azure 存储 HTTP 和 HTTPS,但强烈建议使用 HTTPS。

备注

容器和 blob 可通过设置其容器的权限来允许公共访问。 有关详细信息,请参阅管理对资源Azure 存储的访问权限。 容器、blob、队列或表可以通过共享访问签名进行签名访问;共享访问签名通过不同机制进行授权。 有关 更多详细信息,请参阅使用共享访问签名 委托访问权限。

指定 Date 标头

所有已授权的请求都必须包含协调世界时 (UTC) 时间戳。 可以在 x-ms-date 标头中或在标准 HTTP/HTTPS Date 标头中指定时间戳。 如果在请求中同时指定这两个标头,则使用 x-ms-date 的值作为请求的创建时间。

存储服务确保到请求获得服务时,请求的存在时间不超过 15 分钟。 这能防范某些安全攻击,包括重放攻击。 如果此检查失败,服务器将返回响应码 403(已禁止)。

备注

提供标头是因为某些 HTTP 客户端库和代理会自动设置标头,并且不会为开发人员提供读取其值以在授权请求中包括 x-ms-date Date 它的机会。 如果设置 x-ms-date,则对 Date 标头使用空值来构造签名。

指定 Authorization 标头

授权请求必须包含 Authorization 标头。 如果不包括此标头,则请求将匿名发出,且只有对为实现公共访问而标记的容器或 blob,或者对为实现委托访问而获得共享访问签名的容器、blob、队列或表才能成功。

若要授权请求,必须使用正在请求的帐户的密钥对请求进行签名,并作为请求的一部分传递该签名。

Authorization 标头的格式如下所示:

Authorization="[SharedKey|SharedKeyLite] <AccountName>:<Signature>"  

其中 SharedKeySharedKeyLite 是授权方案的名称,AccountName 是请求资源的帐户的名称,Signature 是基于散列的消息身份验证代码 (HMAC),该代码基于请求构造,并使用 SHA256 算法计算,然后使用 Base64 编码方式进行编码。

备注

如果驻留在不同帐户下的资源是允许公共访问的资源,则可以请求该资源。

以下几节介绍如何构造 Authorization 标头。

构造签名字符串

签名字符串的构造方式取决于要针对哪个服务和版本授权,以及你使用的授权方案。 构造签名字符串时,请注意以下几点:

  • 字符串的 VERB 部分是 HTTP 动词,如 GET 或 PUT,必须为大写形式。

  • 对于 Blob、队列和文件服务的共享密钥授权,签名字符串中包含的每个标头只能显示一次。 如果有任何标头重复,则服务将返回状态码 400(错误请求)。

  • 所有标准 HTTP 标头的值都必须按照签名格式中所示顺序包括在字符串中,且不含头名称。 如果这些标头未指定为请求的一部分,则可能为空;在这种情况下,只需要换行符。

  • 如果指定 x-ms-date 标头,则可以忽略 Date 标头,不管它是否在请求中指定,只需为签名字符串的 Date 部分指定空行。 在这种情况下,请按照构造规范化标头字符串部分的说明添加 x-ms-date 标头。

    可以指定 和 ;在这种情况下,服务 x-ms-date Date 使用 的值 x-ms-date

  • 如果未指定 x-ms-date 标头,请在签名字符串中指定 Date 标头,且不指定标头名称。

  • 签名字符串中必须包含显示的所有换行符 (\n)。

  • 签名字符串包括规范化标头和规范化资源字符串。 规范化这些字符串就是将它们转换为 Azure 存储可以识别的标准格式。 有关构造组成签名字符串的 CanonicalizedHeadersCanonicalizedResource 字符串的详细信息,请参见本主题中后面对应的小节。

Blob、队列和文件服务 (共享密钥授权)

若要针对 2009-09-19 版本及更高版本的 Blob 或队列服务请求以及 2014-02-14 版本及更高版本的文件服务请求为共享密钥签名字符串进行编码,请采用以下格式:

StringToSign = VERB + "\n" +  
               Content-Encoding + "\n" +  
               Content-Language + "\n" +  
               Content-Length + "\n" +  
               Content-MD5 + "\n" +  
               Content-Type + "\n" +  
               Date + "\n" +  
               If-Modified-Since + "\n" +  
               If-Match + "\n" +  
               If-None-Match + "\n" +  
               If-Unmodified-Since + "\n" +  
               Range + "\n" +  
               CanonicalizedHeaders +   
               CanonicalizedResource;  

重要

在当前版本中,如果请求的内容长度为零,则 Content-Length 字段必须是空字符串。 在版本 2014-02-14 及更早版本中,即使为零,也包含内容长度。 有关旧行为的详细信息,请参阅下文。

以下示例演示获取 Blob 操作签名字符串 。 如果没有标头值,则仅指定换行符。

GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Fri, 26 Jun 2015 23:39:12 GMT\nx-ms-version:2015-02-21\n/myaccount/mycontainer\ncomp:metadata\nrestype:container\ntimeout:20  

逐行拆分将显示相同字符串的每一个部分:

GET\n /*HTTP Verb*/  
\n    /*Content-Encoding*/  
\n    /*Content-Language*/  
\n    /*Content-Length (empty string when zero)*/  
\n    /*Content-MD5*/  
\n    /*Content-Type*/  
\n    /*Date*/  
\n    /*If-Modified-Since */  
\n    /*If-Match*/  
\n    /*If-None-Match*/  
\n    /*If-Unmodified-Since*/  
\n    /*Range*/  
x-ms-date:Fri, 26 Jun 2015 23:39:12 GMT\nx-ms-version:2015-02-21\n    /*CanonicalizedHeaders*/  
/myaccount /mycontainer\ncomp:metadata\nrestype:container\ntimeout:20    /*CanonicalizedResource*/  

接下来,对采用 UTF-8 编码的签名字符串使用 HMAC-SHA256 算法进行编码,构造 Authorization 标头,并将该标头添加到请求。 下面的示例是用于相同操作的 Authorization 标头:

Authorization: SharedKey myaccount:ctzMq410TV3wS7upTBcunJTDLEJwMAZuFPfr0mrrA08=  

若要将共享密钥授权与 Blob 和队列服务的版本 2009-09-19 及更高版本一起使用,必须更新代码以使用此扩充签名字符串。

如果希望使用尽可能少的更改将代码迁移到 Blob 和队列服务的版本 2009-09-19 或更高版本,可以修改现有标头以使用共享密钥 Authorization Lite 而不是共享密钥。 共享密钥 Lite 要求的签名格式与 2009-09-19 之前版本的 Blob 和队列服务的共享密钥要求的格式相同。

重要

如果要访问存储帐户中已启用读访问地域复制 (RA-GRS) 的辅助位置,请不要在 authorization 标头中包括 -secondary 指定。 出于授权目的,帐户名称始终是主位置的名称,甚至对于辅助访问也是如此。

版本 2014-02-14 及更早版本中的 Content-Length 标头

使用版本 2014-02-14 或更早版本时,如果 为零,则 将 的 部分 Content-Length Content-Length 设置为 StringToSign 0 。 这通常是一个空字符串。

例如,对于以下请求,即使标头为零,标头的值也 Content-Length StringToSign 包含在 中。

PUT http://myaccount/mycontainer?restype=container&timeout=30 HTTP/1.1  
x-ms-version: 2014-02-14  
x-ms-date: Fri, 26 Jun 2015 23:39:12 GMT  
Authorization: SharedKey myaccount:ctzMq410TV3wS7upTBcunJTDLEJwMAZuFPfr0mrrA08=  
Content-Length: 0

StringToSign构造方式如下:

Version 2014-02-14 and earlier:
PUT\n\n\n\n0\n\n\n\n\n\n\n\nx-ms-date:Fri, 26 Jun 2015 23:39:12 GMT\nx-ms-version:2014-02-14\n/myaccount/mycontainer\nrestype:container\ntimeout:30

而在 2014-02-14 之后的版本中, StringToSign 必须包含 的空字符串 Content-Length

Version 2015-02-21 and later:
PUT\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Fri, 26 Jun 2015 23:39:12 GMT\nx-ms-version:2015-02-21\n/myaccount/mycontainer\nrestype:container\ntimeout:30

表服务 (共享密钥授权)

如果服务使用共享密钥授权来授权针对表服务REST API请求。 表服务共享密钥的签名字符串的格式对所有版本都相同。

针对表服务的请求的共享密钥签名字符串与针对 Blob 或 队列服务 的请求的共享密钥签名字符串略有不同,因为它不包含字符串 CanonicalizedHeaders 的 部分。 此外,这种情况下,Date 标头不会为空,即使请求设置了 x-ms-date 标头也不例外。 如果请求设置 x-ms-date,则也会使用该值作为 Date 标头值。

要对使用 REST API 的表服务请求的签名字符串进行编码,请使用以下格式:

StringToSign = VERB + "\n" +
               Content-MD5 + "\n" +
               Content-Type + "\n" +  
               Date + "\n" +  
               CanonicalizedResource;  

备注

从版本 2009-09-19 开始,表服务要求所有 REST 调用都包括 DataServiceVersionMaxDataServiceVersion 标头。 有关详细信息 ,请参阅设置 OData 数据服务 版本标头。

Blob、队列和文件服务 (共享密钥 Lite 授权)

可以使用共享密钥 Lite 授权来授权针对 2009-09-19 版本及更高版本的 Blob 和队列服务以及文件服务版本 2014-02-14 及更高版本的请求。

共享密钥 Lite 的签名字符串与 2009-09-19 之前的 Blob 和队列服务版本中共享密钥授权所需的签名字符串相同。 因此,如果要将更改次数最少的代码迁移到 Blob 和队列服务版本 2009-09-19,可以修改代码以使用共享密钥 Lite,而无需更改签名字符串本身。 通过使用共享密钥 Lite,你将不会获得通过使用版本 2009-09-19 及更高版本的共享密钥提供的增强的安全性功能。

要对用于 Blob 或队列服务请求的签名字符串进行编码,请使用以下格式:

StringToSign = VERB + "\n" +  
               Content-MD5 + "\n" +  
               Content-Type + "\n" +  
               Date + "\n" +  
               CanonicalizedHeaders +   
               CanonicalizedResource;  

以下示例显示了 Put Blob 操作 签名 字符串。 请注意,Content-MD5 标头行为空。 显示在该字符串中的标头是指定新 Blob 的自定义元数据值的名称/值对。

PUT\n\ntext/plain; charset=UTF-8\n\nx-ms-date:Sun, 20 Sep 2009 20:36:40 GMT\nx-ms-meta-m1:v1\nx-ms-meta-m2:v2\n/testaccount1/mycontainer/hello.txt  

接下来,对采用 UTF-8 编码的签名字符串使用 HMAC-SHA256 算法进行编码,构造 Authorization 标头,并将该标头添加到请求。 下面的示例是用于相同操作的 Authorization 标头:

Authorization: SharedKeyLite myaccount:ctzMq410TV3wS7upTBcunJTDLEJwMAZuFPfr0mrrA08=  

表服务 (共享密钥 Lite 授权)

您可以使用共享密钥 Lite 授权来授权对表服务的任何版本发出的请求。

要对使用共享密钥 Lite 的表服务请求的签名字符串进行编码,请使用以下格式:

StringToSign = Date + "\n"
               CanonicalizedResource  

下面的示例显示了 创建表 操作的签名字符串。

Sun, 11 Oct 2009 19:52:39 GMT\n/testaccount1/Tables  

接下来,使用 HMAC-SHA256 算法对此字符串进行编码,构造 Authorization 标头,然后将该标头添加到请求。 下面的示例是用于相同操作的 Authorization 标头:

Authorization: SharedKeyLite testaccount1:uay+rilMVayH/SVI8X+a3fL8k/NxCnIePdyZSkqvydM=  

构造规范化标头字符串

要构造签名字符串的 CanonicalizedHeaders 部分,请执行以下步骤:

  1. 检索以 x-ms- 开头的所有资源标头,包括 x-ms-date 标头。

  2. 将每个 HTTP 标头名称转换为小写形式。

  3. 以升序基于标头名称按字母顺序对标头进行排序。 每个标头在字符串中只出现一次。

    备注

    字典排序 可能并不总是与传统的字母顺序一致。

  4. 将标头值中的所有线性空格替换为一个空格。

线性空格包括回车符/换行符 (CRLF) 、空格和制表符。 有关详细信息,请参阅 RFC 2616,第4.2 节 。 请勿替换带引号的字符串内的任何空白。

  1. 在标头中的冒号前后剪裁任意空白。

  2. 最后,在产生的列表中的每一个规范化标头之后追加一个换行符。 将此列表中的所有标头连接起来成为一个字符串,构造 CanonicalizedHeaders 字符串。

下面演示了规范化标头字符串的示例:

x-ms-date:Sat, 21 Feb 2015 00:48:38 GMT\nx-ms-version:2014-02-14\n

备注

在 service 版本2016-05-31 之前,会从签名字符串中省略包含空值的标头。 现在,通过在规范化标头后跟终止的新行来表示这些字符串。

构造规范化资源字符串

签名字符串的 CanonicalizedResource 部分表示要请求的存储服务资源。 源自资源 URI 的CanonicalizedResource 字符串的任何部分都应该安全按照其在 URI 中的形式进行编码。

对于 CanonicalizedResource 字符串,支持以下两种格式:

  • 一种格式,支持对 Blob 和队列服务版本2009-09-19 及更高版本以及文件服务版本2014-02-14 及更高版本的共享密钥授权。

  • 一种格式支持用于所有版本表服务的共享密钥和共享密钥 Lite,以及用于 2009-09-19 版本及更高版本 Blob 和队列服务的共享密钥 Lite。 此格式与用于先前版本的存储服务的格式相同。

有关为要访问的资源构造 URI 的帮助,请参见以下主题之一:

重要

如果你使用读取访问地域复制 (RA-GRS) 复制存储帐户,并且要访问辅助位置中的资源,请不要在 –secondary 字符串中包括 CanonicalizedResource 指定。 CanonicalizedResource 字符串 URI 中使用的资源 URI 应是主位置资源的 URI。

备注

如果要针对存储模拟器进行授权,则帐户名称将在字符串中出现两次 CanonicalizedResource 。 这是正常情况。 如果针对 Azure 存储服务进行授权,则帐户名在字符串中将只出现一次 CanonicalizedResource

2009-09-19 及更高版本的共享密钥格式

此格式支持对2009-09-19 版本及更高版本的 Blob 和队列服务以及2014-02-14 版本及更高版本的文件服务进行共享密钥授权。 按照如下格式构造 CanonicalizedResource 字符串:

  1. 以空字符串 ("") 开头,随后追加一个正斜杠 (/),再接拥有待访问资源的帐户的名称。

  2. 不带任何查询参数,附加该资源的编码 URI 路径。

  3. 检索资源 URI 的所有查询参数,包括 comp 参数(如果有)。

  4. 将所有参数名称转换为小写形式。

  5. 以升序基于参数名称按字母顺序对查询参数进行排序。

  6. 对每个查询参数名称和值进行 URL 解码。

  7. 在每个名称-值对\n) 包含一个新行字符 (。

  8. 按以下格式在该字符串之后附加每个查询参数名称和值,并确保在名称与值之间使用冒号 (:):

    parameter-name:parameter-value

  9. 如果一个查询参数具有多个值,请按字母顺序将所有值进行排序,然后以逗号分隔列表的形式包括这些值:

    parameter-name:parameter-value-1,parameter-value-2,parameter-value-n

记住以下规则以构造规范化资源字符串:

  • 避免在查询参数的值中使用换行符 (\n)。 如果必须使用换行符,请确保它不会影响规范化资源字符串的格式。

  • 避免在查询参数值中使用逗号。

下面是一些示例,演示可基于给定请求 URI 构造的签名字符串 CanonicalizedResource 部分:

Get Container Metadata  
   GET http://myaccount.blob.core.windows.net/mycontainer?restype=container&comp=metadata
CanonicalizedResource:  
    /myaccount/mycontainer\ncomp:metadata\nrestype:container  
  
List Blobs operation:  
    GET http://myaccount.blob.core.windows.net/container?restype=container&comp=list&include=snapshots&include=metadata&include=uncommittedblobs  
CanonicalizedResource:  
    /myaccount/mycontainer\ncomp:list\ninclude:metadata,snapshots,uncommittedblobs\nrestype:container  
  
Get Blob operation against a resource in the secondary location:  
   GET https://myaccount-secondary.blob.core.windows.net/mycontainer/myblob  
CanonicalizedResource:  
    /myaccount/mycontainer/myblob

2009-09-19 及更高版本的共享密钥 Lite 和表服务格式

对于所有版本的表服务,此格式支持共享密钥和共享密钥 Lite;对于 2009-09-19 版本及更高版本的 Blob 和队列服务以及 2014-02-14 版本及更高版本的文件服务,此格式支持共享密钥 Lite。 此格式与用于先前版本的存储服务的格式相同。 按照如下格式构造 CanonicalizedResource 字符串:

  1. 以空字符串 ("") 开头,随后追加一个正斜杠 (/),再接拥有待访问资源的帐户的名称。

  2. 附加资源的编码 URI 路径。 如果请求 URI 找到了资源的一个组件,则附加相应的查询字符串。 该查询字符串应该包括问号和 comp 参数(例如 ?comp=metadata)。 查询字符串中不应该包括其他任何参数。

编码签名

要对签名进行编码,请对 UTF-8 编码的签名字符串调用 HMAC-SHA256 算法,并将结果编码为 Base64 格式。 请注意,还需要对存储帐户密钥进行 Base64 解码。 使用以下格式(显示为伪代码):

Signature=Base64(HMAC-SHA256(UTF8(StringToSign), Base64.decode(<your_azure_storage_account_shared_key>)))  

请参阅