我在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)
};
}
然后我在客户端调用此网址,然后尝试使用以下代码上传:
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}`;
哪个生成这样的网址:
哪个返回此错误:
403(服务器无法验证请求。请确保 授权标头的格式正确,包括签名。)
如果我从azure门户网站生成了sas令牌,则它可以正常工作,因此生成的url如下所示:
但是我的网址看起来像这样:
我不知道该怎么做
答案 0 :(得分:0)
您的Azure功能代码正确,并且
var sasToken = blobService.generateSharedAccessSignature(
container,
blobName,
sharedAccessPolicy
);
正是您上传blob所需的sasToken。无需像第二个代码片段中那样再次处理令牌(实际上是错误处理)。
预计Azure门户(Account SAS)中的sas令牌与代码(Service SAS)中生成的sas令牌不同。看看doc。
总结
确保连接字符串属于您要连接的存储。您可以避免麻烦,直接将var connString = process.env.AzureWebJobsStorage;
替换为var connString = "connectionStringGotFromPortal";
如果确认为1,则您的Azure函数代码正确,并按预期返回令牌
{
token: sasToken,
uri: blobService.getUrl(container, blobName, sasToken, true)
};
根据您提供的第二个代码段,您只需要
return `${url}/${containerName}/${filename}?${token}`;
如果令牌与返回的函数相同。
答案 1 :(得分:0)
问题在于,在服务器端代码中,您正在创建Service SAS
,然后仅获取代码的签名部分(sig
),并在客户端上创建Account SAS
。
由于用于创建令牌的参数现已更改(在原始参数中,您没有诸如ss
,srt
等的参数,但是在创建自己的URL时,插入这些参数),那么当您使用修改后的SAS URL时,会出现403错误。发生这种情况是因为服务器再次基于URL参数计算签名,并将其与URL中传递的签名进行比较。由于两个签名不匹配,因此您将收到403错误。
由于您要返回Blob的SAS URL,因此无需在客户端上创建URL。您可以简单地使用从客户端API层返回的uri
并使用该文件进行上传。
答案 2 :(得分:0)
正如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`} }
);