【问题标题】:Authorization Header to Azure Tables fails with 403 "Authoization header malformed"Azure 表的授权标头失败,出现 403“授权标头格式错误”
【发布时间】:2020-04-27 15:09:45
【问题描述】:

我拼凑了代码以授权 Microsoft Azure 进行存储帐户表操作。

function TAzureStorageAPI.GetAuthHeader(RequestMethod,Ressource,Time:UTF8String): String;

Var
  KeyBytes:TBytes;
  DataBytes:TBytes;
  TimeString,
  StringtoSign:UTF8String;

begin
  StringtoSign:=Uppercase(RequestMethod)+LF+                                  //RequestMethod
                ''+LF+                                                        //contentMD5
                'application/json; charset=ISO-8859-1'+LF+                                //contentType
                TimeString+LF+                                                //requestDate
                Ressource;                                                    //Ressource
  keyBytes:=TNetEncoding.Base64.DecodeStringToBytes(FAccessKey);
  dataBytes:=TEncoding.UTF8.GetBytes(StringToSign);
  result:= (TNetEncoding.Base64.EncodeBytesToString(THashSHA2.GetHMACAsBytes(dataBytes, keyBytes)));
end;

function TAzureStorageAPI.Insert(PartitionKey,RowKey:String; Data:tlkJSONObject):tlkJSONObject;

Var
  PostHeaders:TStringlist;
  Time:TDateTime;
  TimeString:String;

begin
  Socket.Request.Accept:='application/json;odata=minimalmetadata';
  PostHeaders:=TStringlist.Create;
  PostHeaders.Add('x-ms-version:2019-07-07');
  Time:=TTimeZone.Local.ToUniversalTime(Now);
  TimeString:=FormatDateTime('ddd, dd mmm yyyy hh:nn:ss',Time)+' UTC';
  PostHeaders.Add('Date:'+TimeString);
  PostHeaders.Add('MaxDataServiceVersion:3.0;NetFx');
  PostHeaders.Add('DataServiceVersion:3.0;NetFx');
  PostHeaders.Add('Authorization:SharedKey '+FStorageAccount+':'+GetAuthHeader('post','/'+FStorageAccount+'/'+FTable,TimeString));
  Host:=FStorageAccount+'.table.core.windows.net';
  Data.Add('PartitionKey',PartitionKey);
  Data.add('RowKey',RowKey);
  result:=WebPostData('/'+FTable,PostHeaders,Data)as tlkJSONObject;
  PostHeaders.Free;
end;
  • StorageAccount 是我从 SharedKey-Options 获得的名称
  • Table 是来自 Table Service 的资源的名称
  • AccessKey 是 SharedKey-Options 中的 Key1

StringToSign 是

'POST'#$A#$A'application/json; charset=ISO-8859-1'#$A'Mo, 27 Apr 2020 18:02:33 UTC'#$A'/smartflatlog/Log'

我没有对资源使用任何访问策略。

修复报头传递中的错误后,我在线路上看到以下传输:

Ges 27.04.2020 20:02:48: POST /Log HTTP/1.1<EOL>Content-Type: application/json; charset=ISO-8859-1<EOL>Content-Length: 104<EOL>x-ms-version: 2019-07-07<EOL>Date: Mo, 27 Apr 2020 18:02:33 UTC<EOL>MaxDataServiceVersion: 3.0;NetFx<EOL>DataServiceVersion: 3.0;NetFx<EOL>Authorization: SharedKey smartflatlog:KVtJ*********************************A5zOME=<EOL>Host: smartflatlog.table.core.windows.net<EOL>Accept: application/json;odata=minimalmetadata<EOL>User-Agent: Demo<EOL><EOL>
Ges 27.04.2020 20:02:48: {"Level":"Debug","LogText":"something to note","Application":"Demo","PartitionKey":"Demo","RowKey":"13"}
Erh 27.04.2020 20:02:48: HTTP/1.1 403 Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.<EOL>Content-Length: 299<EOL>Content-Type: application/json<EOL>Server: Microsoft-HTTPAPI/2.0<EOL>x-ms-request-id: 86f7fd8d-2002-0021-63be-1c5d47000000<EOL>x-ms-error-code: AuthenticationFailed<EOL>Date: Mon, 27 Apr 2020 18:02:49 GMT<EOL><EOL>{"odata.error":{"code":"AuthenticationFailed","message":{"lang":"en-US","value":"Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.\nRequestId:86f7fd8d-2002-0021-63be-1c5d47000000\nTime:2020-04-27T18:02:49.6860540Z"}}}

【问题讨论】:

  • 您似乎正试图在表中插入一个实体。您可以通过 Fiddler 跟踪请求/响应吗?这应该会为您提供有关错误的更多详细信息。
  • 啊,在 send-socket 方法的深处有一个错误,无法添加标头 :-( 谢谢提示,现在我得到“授权标头无效”,但我会打开一个新帖子。
  • 无需提出新问题 :)。只需更新问题的标题并提供最新的代码即可。
  • 再次,请检查 Fiddler 响应。通常它应该告诉您存储服务用于计算StringtoSign 的数据。请在您的问题中也包括在内。
  • 另外,请包含您的StringtoSign 变量值。

标签: azure delphi azure-table-storage


【解决方案1】:

如果你想插入一个带有 Sharekey 身份验证的实体,stringtosign 应该是这样的

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

例如

 RequestMethod:= 'GET';

  dateInRfc1123Format:= TTimeZone.Local.ToUniversalTime(Now);
  TheDate:= formatdatetime('ddd, dd mmm yyyy hh:nn:ss "GMT"',dateInRfc1123Format);
  contentType:='application/json;odata=nometadata'
canonicalizedResource:= "/yourAccount/yourTable"
 stringToSign:= format('%s\n'+ // request method

                        '\n' + // content md5
                        '%s\n' + // content type
                        '%s\n' + // date
                        '%s', // canonicalized ResourceL,
                        [RequestMethod,
                        contentType,
                        TheDate,
                        canonicalizedResource]);

更多详情请参考documentdocument

【讨论】:

  • 但这正是我正在做的!但是您没有使用内容类型,而是 stingtosign 中接受的类型....
  • @WolfgangBuresw 关于内容类型,请参考docs.microsoft.com/en-us/rest/api/storageservices/insert-entity
  • 我对这些文章了如指掌。 :-) 您在上面的代码中显示的内容与我阅读它的方式有些不同。您在 StringtoSign 中使用 ACCEPT 标头而不是 CONTENT-TYPE。我确实测试了你的方法,我必须说没有运气。
  • @WolfgangBures 请尽量不要在 StringtoSign 中提供内容类型值
  • 所以这在分隔符为 CRLF、LF 或 "\n" 时都不起作用。 StringtoSign:=Uppercase(RequestMethod)+Separator+ //RequestMethod ''+Separator+ //contentMD5 ''+Separator+ //contentType Time+Separator+ //requestDate Ressource; //资源
猜你喜欢
  • 2017-03-07
  • 2016-02-24
  • 2019-10-29
  • 1970-01-01
  • 2021-09-24
  • 1970-01-01
  • 2017-11-23
  • 2021-02-21
  • 2019-11-23
相关资源
最近更新 更多