繁体   English   中英

使用JS生成Azure Blob存储SA令牌

[英]Azure blob storage sas token generation using js

我在azure函数中运行此函数,以获取用于浏览器应用程序的sas令牌,以上传到azure blob存储:

var azure = require('azure-storage');

module.exports = function(context, req) {
  if (req.body.container) {
    // The following values can be used for permissions:
    // "a" (Add), "r" (Read), "w" (Write), "d" (Delete), "l" (List)
    // Concatenate multiple permissions, such as "rwa" = Read, Write, Add
    context.res = generateSasToken(
      context,
      req.body.container,
      req.body.blobName,
      req.body.permissions
    );
  } else {
    context.res = {
      status: 400,
      body: "Specify a value for 'container'"
    };
  }

  context.done(null, context);
};

function generateSasToken(context, container, blobName, permissions) {
  var connString = process.env.AzureWebJobsStorage;
  var blobService = azure.createBlobService(connString);

  // Create a SAS token that expires in an hour
  // Set start time to five minutes ago to avoid clock skew.
  var startDate = new Date();
  startDate.setMinutes(startDate.getMinutes() - 5);
  var expiryDate = new Date(startDate);
  expiryDate.setMinutes(startDate.getMinutes() + 60);

  permissions = azure.BlobUtilities.SharedAccessPermissions.READ +
                azure.BlobUtilities.SharedAccessPermissions.WRITE +
                azure.BlobUtilities.SharedAccessPermissions.DELETE +
                azure.BlobUtilities.SharedAccessPermissions.LIST;

  var sharedAccessPolicy = {
    AccessPolicy: {
      Permissions: permissions,
      Start: startDate,
      Expiry: expiryDate
    }
  };

  var sasToken = blobService.generateSharedAccessSignature(
    container,
    blobName,
    sharedAccessPolicy
  );

  context.log(sasToken);

  return {
    token: sasToken,
    uri: blobService.getUrl(container, blobName, sasToken, true)
  };
}

然后,我在客户端调用此url,然后尝试使用以下代码上传:

const search = new URLSearchParams(`?${token}`);

const sig = encodeURIComponent(search.get('sig'));

const qs = `?sv=${search.get('sv')}&ss=b&srt=sco&sp=rwdlac&se=${search.get('sv')}&st=${search.get(
  'st'
)}&spr=https&sig=${sig}`;

return `${url}/${containerName}/${filename}${qs}`;

会生成如下网址:

https://mystorage.blob.core.windows.net/mycontainer/latest.png?sv=2018-03-28&ss=b&srt=sco&sp=rwdlac&se=2018-03-28&st=2019-01-30T19:11:10Z&spr= HTTPS&SIG = g0sceq3EkiAQTvyaZ07C + C4SZQz9FaGTV4Zwq4HkAnc =

哪个返回此错误:

403(服务器无法验证请求。确保正确构成了包括签名的Authorization标头的值。)

如果我从azure门户生成sas令牌,则它可以正常工作,因此生成的url如下所示:

https://mystorage.blob.core.windows.net/mycontainer/latest.png?sv=2018-03-28&ss=b&srt=sco&sp=rwdlac&se=2019-01-31T03:01:43Z&st=2019-01-30T19: 01:43Z&SPR = HTTPS&SIG = ayE4gt%2FDfDzjv5DjMaD7AS%2F176Bi4Q6DWJNlnDzl%2FGc%3D

但我的网址看起来像这样:

https://mystorage.blob.core.windows.net/mycontainer/latest.png?sv=2018-03-28&ss=b&srt=sco&sp=rwdlac&se=2019-01-31T03:34:21Z&st=2019-01-30T19: 34:21Z&SPR = HTTPS&SIG = Dx8Vm4XPnD1rn9uyzIAXZEfcdbWb0HjmOq%2BIq42Q%2FOM%3D

我不知道该怎么做才能使这个工作

您的Azure函数代码正确,并且

var sasToken = blobService.generateSharedAccessSignature(
    container,
    blobName,
    sharedAccessPolicy
);

正是您需要上传blob的sasToken。 无需像第二个代码片段中那样再次处理令牌(实际上是错误处理)。

预期Azure门户(Account SAS)中的sas令牌与代码(Service SAS)中生成的sas令牌不同。 看一下doc

总而言之,

  1. 确保连接字符串属于您要连接的存储。 您可以避免麻烦,直接替换为var connString = process.env.AzureWebJobsStorage; var connString = "connectionStringGotFromPortal";

  2. 如果确认为1,则您的Azure函数代码正确,并按预期返回令牌

     { token: sasToken, uri: blobService.getUrl(container, blobName, sasToken, true) }; 
  3. 根据您提供的第二个代码段,您只需要

     return `${url}/${containerName}/${filename}?${token}`; 

    如果令牌与返回的函数相同。

问题在于,在服务器端代码中,您正在创建Service SAS ,然后仅获取代码的签名部分( sig ),并在客户端上创建Account SAS

由于用于创建令牌的参数现已更改(在原始参数中,您没有sssrt等参数,但是在创建自己的URL时将插入这些参数),修改SAS URL,您将得到403错误。 发生这种情况是因为服务器再次基于URL参数计算签名,并将其与URL中传递的签名进行比较。 由于两个签名不匹配,因此出现403错误。

由于返回的是blob的SAS URL,因此无需在客户端上创建URL。 您可以简单地使用从客户端API层返回的uri ,并使用该uri进行上传。

正如Jerry Liu的答案所解释的那样,您的Azure函数会生成正确的令牌,并且已经为您提供了正确的uri使用,其中包括您的Blob名称和令牌。

在您的客户端,您还可以使用azure-sdk-for-js

// This is the response from your api with token and uri    
const uri = response.uri;

const pipeline = StorageURL.newPipeline(new AnonymousCredential());

// Your uri already includes the full blob url with SAS signature
const blockBlobURL = BlockBlobURL.fromBlobURL(new BlobURL(uri, pipeline));
const uploadBlobResponse = await blockBlobURL.upload(
  Aborter.none,
  file,
  file.size,
  { blobHTTPHeaders: { blobContentType: `${mime}; charset=utf-8`} }
);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM