如何为 Azure 存储生成帐户 SAS 令牌?

cod*_*erk 3 javascript azure azure-storage node.js

理想情况下,我想访问存储中的所有容器和 blob。帐户 SAS 令牌是在我的代码中生成的服务器端。客户端将调用我在 Node.js 中创建的 API 来接收它。我看到您可以使用 Azure Shell 手动创建 SAS 令牌,但我更喜欢在服务端生成它,因为将实施身份验证。

按照帐户 SAS 生成文档,它指出应该像这样构造要签名的字符串。

StringToSign = accountname + "\n" +  
    signedpermissions + "\n" +  
    signedservice + "\n" +  
    signedresourcetype + "\n" +  
    signedstart + "\n" +  // optional
    signedexpiry + "\n" +  
    signedIP + "\n" +  // optional
    signedProtocol + "\n" +  // optional
    signedversion + "\n" 
Run Code Online (Sandbox Code Playgroud)

文档中的示例令牌(为了更好的可见性,分成多行)

sv=2019-02-02&ss=bf&srt=s&st=2019-08-01T22%3A18%3A26Z
&se=2019-08-10T02%3A23%3A26Z&sr=b&sp=rw
&sip=168.1.5.60-168.1.5.70&spr=https
&sig=F%6GRVAZ5Cdj2Pw4tgU7IlSTkWgn7bUkkAg8P6HESXwmf%4B
Run Code Online (Sandbox Code Playgroud)

从 Azure Shell 生成的令牌

se=2019-11-15&sp=rwdlac&sv=2018-03-28&ss=b&srt=sco&sig=<hidden signature>
Run Code Online (Sandbox Code Playgroud)

奇怪的是,在示例令牌中,首先提供了signedversion (sv),而在 Azure Shell 的令牌中提供了signedexpiry (se)

下面是用于生成令牌的代码。我尝试遵循与 Azure Shell 中的令牌相同的顺序:

app.get('/sas-token', (req, res, next) => {

  // const start = new Date(new Date().getTime() - (15 * 60 * 1000));
  const end = new Date(new Date().getTime() + (30 * 60 * 1000));

  const signedpermissions = 'rwdlac';
  const signedversion = '2018-03-28';
  const signedservice = 'b';
  const signedresourcetype = 'sco';
  // const signedstart = truncateIsoDate(start);
  const signedexpiry = truncateIsoDate(end);
  // const signedIP = '';
  const signedProtocol = 'https';

  const StringToSign = STORAGE_ACCOUNT_NAME + "\n" +
      signedpermissions + "\n" +
      signedservice + "\n" +
      signedresourcetype + "\n" +
      // signedstart + "\n" +  
      signedexpiry + "\n" +
      // signedIP + "\n" +  
      signedProtocol + "\n" +
      signedversion + "\n"

  const key = new Buffer(ACCOUNT_ACCESS_KEY, 'base64');
  let sig = crypto.createHmac('sha256', key).update(StringToSign, 'utf8').digest('base64');

  let sas =
    `se=${signedexpiry}
     &sp=${(signedpermissions)}
     &sv=${(signedversion)}
     &ss=${(signedservice)}
     &srt=${(signedresourcetype)}
     &sig=${encodeURIComponent(sig)}`;

  res.json({
      storageUri: STORAGE_ACCOUNT_NAME,
      storageAccessToken: sas
  });
});
Run Code Online (Sandbox Code Playgroud)

当我的客户最终使用生成的 SAS 令牌发出请求时,我收到一个错误:

403 (Server failed to authenticate the request. 
Make sure the value of Authorization header is formed correctly including the signature.)
Run Code Online (Sandbox Code Playgroud)

是否可以在 Node.js 中为 Blob 存储生成帐户 SAS 令牌

Jim*_* Xu 7

根据我的研究,我们可以使用 Azure 存储 SDK azure-storage。更多详情请参考https://github.com/Azure/azure-storage-node/blob/0557d02cd2116046db1a2d7fc61a74aa28c8b557/test/accountsas-tests.js

var storage = require("azure-storage")
var startDate = new Date();
    var expiryDate = new Date();
    startDate.setTime(startDate.getTime() - 5*60*1000);
    expiryDate.setTime(expiryDate.getTime() + 24*60*60*1000);
    var AccountSasConstants = storage.Constants.AccountSasConstants;
    var sharedAccessPolicy = {
      AccessPolicy: {
        Services: AccountSasConstants.Services.BLOB ,
        ResourceTypes: AccountSasConstants.Resources.SERVICE + 
                       AccountSasConstants.Resources.CONTAINER +
                       AccountSasConstants.Resources.OBJECT,
        Permissions: AccountSasConstants.Permissions.READ + 
                     AccountSasConstants.Permissions.ADD +
                     AccountSasConstants.Permissions.CREATE +
                     AccountSasConstants.Permissions.WRITE +
                     AccountSasConstants.Permissions.DELETE +
                     AccountSasConstants.Permissions.LIST,
        Protocols: AccountSasConstants.Protocols.HTTPSORHTTP,
        Start: startDate,
        Expiry: expiryDate
      }
      
    };
    const accountname ="blobstorage0516";
    const key = "";
    var sas =storage.generateAccountSharedAccessSignature(accountname,key,sharedAccessPolicy);
    console.log(sas);
Run Code Online (Sandbox Code Playgroud)

此外,如果您不想使用SDK生成SAS令牌,请注意,\n如果我们不使用其中的一个属性,我们不能省略,StringToSign并且我们在StringToSign创建sas令牌时应该使用我们提供的属性。例如

const accountname ="blobstorage0516";
    const key = "";

    const start = new Date(new Date().getTime() - (15 * 60 * 1000));
        const end = new Date(new Date().getTime() + (30 * 60 * 1000));
    const signedpermissions = 'rwdlac';
        const signedservice = 'b';
        const signedresourcetype = 'sco';
        const signedexpiry = end.toISOString().substring(0, end.toISOString().lastIndexOf('.')) + 'Z';
        const signedProtocol = 'https';
        const signedversion = '2018-03-28';

        const StringToSign =
            accountname + '\n' +
            signedpermissions + '\n' +
            signedservice + '\n' +
            signedresourcetype + '\n' +
             '\n' +
            signedexpiry + '\n' +
             '\n' +
            signedProtocol + '\n' +
      signedversion + '\n';
      
    let sig = crypto.createHmac('sha256', Buffer.from(key, 'base64')).update(StringToSign, 'utf8').digest('base64');
  
    let sasToken =
      `sv=${(signedversion)}&ss=${(signedservice)}&srt=${(signedresourcetype)}&sp=${(signedpermissions)}&se=${encodeURIComponent(signedexpiry)}&spr=${(signedProtocol)}&sig=${encodeURIComponent(sig)}`;
    console.log(sasToken)
    var storageBlobEndpoint = "https://"+ accountname +".blob.core.windows.net"
    var container="blobcontainer";
    var blobName="CP4.png";
    var requestURL = storageBlobEndpoint + "/" + container + "/" + blobName +"?"+sasToken
    console.log(requestURL)
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明 在此处输入图片说明


更新

根据我的测试,我们可以使用上面代码创建的 sas token 在 Azure blob 存储上做 smoe 操作。例如

1. 列出容器

Get https://<your account>.blob.core.windows.net/?comp=list+ "&"+"<your sas token>"
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明 在此处输入图片说明

2.获取容器属性

Get https://<your account>.blob.core.windows.net/<your container>?restype=container&comp=list +"&" +"<your sas token>"
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明 另外,关于如何使用新的sdk@azure/storage-blob创建SAS token,请参考以下代码

const accountname ="blobstorage0516";
    const key = "";
    const signedpermissions = 'rwdlac';
        const signedservice = 'b';
        const signedresourcetype = 'sco';
        
        const signedProtocol = 'https';
        const signedversion = '2018-03-28';
    const cerds = new storage.StorageSharedKeyCredential(accountname,key);
    var startDate = new Date();
    var expiryDate = new Date();
    startDate.setTime(startDate.getTime() - 5*60*1000);
    expiryDate.setTime(expiryDate.getTime() + 24*60*60*1000);
    expiryDate.setTime(expiryDate.getTime() + 24*60*60*1000);
    var result = storage.generateAccountSASQueryParameters({
      expiresOn : expiryDate,
      permissions: storage.AccountSASPermissions.parse(signedpermissions),
      protocol: storage.SASProtocol.Https,
      resourceTypes: storage.AccountSASResourceTypes.parse(signedresourcetype).toString(),
      services: storage.AccountSASServices.parse(signedservice).toString(),
      startsOn: startDate,
      version:signedversion

    },cerds).toString();
    console.log(result);
    
Run Code Online (Sandbox Code Playgroud)