REST API已于2月发布,用于设置blob CORS property,但尚未针对NodeJS实施。
由于我需要此功能,我尝试在运行NodeJS的azure网站的模块中实现它。
基于REST API文档to change CORS properties和generate authentification key,在this使用NodeJS实现身份验证密钥生成时,我尝试按照this帖子中接受的答案,但它对我不起作用。
以下是我在setcrosproperties.js中的内容:
var crypto = require('crypto');
var request = require('request');
exports.setCors = function (MY_ACCOUNT_URL, MY_ACCOUNT_NAME, MY_ACCOUNT_HOST, accountKey) {
var MY_CORS_XML =
'<?xml version="1.0" encoding="utf-8"?>'+
'<StorageServiceProperties>'+
'<Cors>'+
'<CorsRule>'+
'<AllowedOrigins>*</AllowedOrigins>'+
'<AllowedMethods>GET,PUT</AllowedMethods>'+
'<MaxAgeInSeconds>500</MaxAgeInSeconds>'+
'<ExposedHeaders>x-ms-meta-data*,x-ms-meta-customheader</ExposedHeaders>'+
'<AllowedHeaders>x-ms-meta-target*,x-ms-meta-customheader</AllowedHeaders>'+
'</CorsRule>'+
'</Cors>'+
'<DefaultServiceVersion>2013-08-15</DefaultServiceVersion>'+
'</StorageServiceProperties>';
var url = MY_ACCOUNT_URL + '/?restype=service&comp=properties';
var canonicalizedResource = '/' + MY_ACCOUNT_NAME + '/?comp=properties';
var corsMD5 = crypto.createHash('md5' ).update(MY_CORS_XML).digest('base64');
var date = (new Date()).toUTCString();
var headers = {
'x-ms-version': '2013-08-15',
'x-ms-date': date,
'Host': MY_ACCOUNT_HOST
};
var canonicalizedHeaders = buildCanonicalizedHeaders( headers );
// THIS
var key = buildSharedKeyLite( 'PUT', corsMD5, 'text/plain; charset=UTF-8', canonicalizedHeaders, canonicalizedResource, accountKey);
// AND THIS, BOTH YIELD THE SAME SERVER RESPONSE
// var key = buildSharedKeyLite( 'PUT', "", "", canonicalizedHeaders, canonicalizedResource, accountKey);
headers['Authorization'] = 'SharedKeyLite ' + MY_ACCOUNT_NAME + ':' + key;
var options = {
url: url,
body: MY_CORS_XML,
headers: headers
};
console.log("url : " + url);
console.log("canonicalizedResource : " + canonicalizedResource);
console.log("canonicalizedHeaders : " + canonicalizedHeaders);
console.log("corsMD5 : " + corsMD5);
console.log("key : " + key);
console.log("options : " + JSON.stringify(options));
function onPropertiesSet(error, response, body) {
if (!error && response.statusCode == 202) {
console.log("CORS: OK");
}
else {
console.log("CORS: " + response.statusCode);
console.log("body : " + body);
}
}
request.put(options, onPropertiesSet); // require('request')
};
function buildCanonicalizedHeaders( headers ) {
var xmsHeaders = [];
var canHeaders = "";
for ( var name in headers ) {
if ( name.indexOf('x-ms-') == 0 ) {
xmsHeaders.push( name );
}
}
xmsHeaders.sort();
for ( var i = 0; i < xmsHeaders.length; i++ ) {
name = xmsHeaders[i];
canHeaders = canHeaders + name.toLowerCase().trim() + ':' + headers[name] + '\n';
}
return canHeaders;
}
function buildSharedKeyLite( verb, contentMD5, contentType, canonicalizedHeaders, canonicalizedResource, accountKey) {
var stringToSign = verb + "\n" +
contentMD5 + "\n" +
contentType + "\n" +
"" + "\n" + // date is to be empty because we use x-ms-date
canonicalizedHeaders +
canonicalizedResource;
// return crypto.createHmac('sha256', accountKey).update(encodeURIComponent(stringToSign)).digest('base64');
return crypto.createHmac('sha256', new Buffer(accountKey, 'base64')).update(stringToSign).digest('base64');
}
以下是我从server.js文件中调用此函数的方法:
var setcrosproperties = require('./setcrosproperties.js');
// setCors(MY_ACCOUNT_URL, MY_ACCOUNT_NAME, MY_ACCOUNT_HOST, accountKey)
setcrosproperties.setCors(
'https://'+process.env['AZURE_STORAGE_ACCOUNT']+'.blob.core.windows.net',
process.env['AZURE_STORAGE_ACCOUNT'],
process.env['AZURE_STORAGE_ACCOUNT']+'.blob.core.windows.net',
process.env['AZURE_STORAGE_ACCESS_KEY']);
我不明白与变量MY_ACCOUNT_UTL(我假设的URL)和MY_ACCOUNT_HOST的差异是什么,所以我对函数的两个参数使用相同的值。
(我删除了“cors”参数,似乎未使用。)
以下是我在控制台中获得的内容:
网址:https://NAME_OF_MY_STORAGE_ACCOUNT.blob.core.windows.net/?restype=service&comp=properties canonicalizedResource:/ NAME_OF_MY_STORAGE_ACCOUNT /?comp = properties canonicalizedHeaders:x-ms-date:Sun,09 Mar Mar 12:33:41 GMT X-MS-版本:2013-08-15 corsMD5:+ ij ... w == key:sNB ... JrY = 选项:{“url”:“https://NAME_OF_MY_STORAGE_ACCOUNT.blob.core.windows.net/?restype=service&comp=properties”,“body”:“ GET,PUT500x-ms-meta-data ,x-ms-meta-customheaderx-ms-meta-target *,x-ms-meta-customheader2013-08-15“,”header“:{”x-ms-version“:”2013-08-15“,”x-ms-date“:”Sun,2014年3月9日12:33:41 GMT“,”主持人“:”NAME_OF_MY_STORAGE_ACCOUNT.blob.core.windows.net“,”授权“:”SharedKeyLite NAME_OF_MY_STORAGE_ACCOUNT:sNB ... rY =“}} CORS:403 body:
AuthenticationFailed
服务器无法验证请求。确保正确形成Authorization标头的值,包括签名。 请求ID:1e6abfe3-e0e8-4b9c-922D-7cb34485eec9 时间:2014-03-09T12:33:41.7262308Z在HTTP请求'sNB中找到的MAC签名... JrY ='与任何计算签名不同。服务器使用以下字符串进行签名:'PUTx-ms-date:太阳报,2014年3月9日12:33:41 GMT X-MS-版本:2013-08-15 / NAME_OF_MY_STORAGE_ACCOUNT /?排版=属性。
对我在这里做错了什么的想法?谢谢你的帮助
答案 0 :(得分:7)
要配置CORS,请使用Node.js的Azure存储库。
你可以npm install azure-storage
来获取它。源代码位于https://github.com/Azure/azure-storage-node。
与npm包azure
(a.k.a。azure-sdk-for-node
)一起使用的那个使用旧的azure-storage-legacy
包,它不支持CORS。
您可以使用以下代码设置CORS:
var service = azure.createBlobService();
var serviceProperties = {
Cors: {
CorsRule: [{
AllowedOrigins: ['*'],
AllowedMethods: ['GET'],
AllowedHeaders: [],
ExposedHeaders: [],
MaxAgeInSeconds: 60
}]
}
};
service.setServiceProperties(serviceProperties, callback);
答案 1 :(得分:1)
请在Content-Type
数组中添加Content-MD5
和headers
,这应该可以解决问题。这是修改后的代码:
var crypto = require('crypto');
var request = require('request');
exports.setCors = function (MY_ACCOUNT_URL, MY_ACCOUNT_NAME, MY_ACCOUNT_HOST, accountKey) {
var MY_CORS_XML =
'<?xml version="1.0" encoding="utf-8"?>'+
'<StorageServiceProperties>'+
'<Cors>'+
'<CorsRule>'+
'<AllowedOrigins>*</AllowedOrigins>'+
'<AllowedMethods>GET,PUT</AllowedMethods>'+
'<MaxAgeInSeconds>500</MaxAgeInSeconds>'+
'<ExposedHeaders>x-ms-meta-data*,x-ms-meta-customheader</ExposedHeaders>'+
'<AllowedHeaders>x-ms-meta-target*,x-ms-meta-customheader</AllowedHeaders>'+
'</CorsRule>'+
'</Cors>'+
'<DefaultServiceVersion>2013-08-15</DefaultServiceVersion>'+
'</StorageServiceProperties>';
var url = MY_ACCOUNT_URL + '/?restype=service&comp=properties';
var canonicalizedResource = '/' + MY_ACCOUNT_NAME + '/?comp=properties';
var corsMD5 = crypto.createHash('md5' ).update(MY_CORS_XML).digest('base64');
var date = (new Date()).toUTCString();
var headers = {
'x-ms-version': '2013-08-15',
'x-ms-date': date,
'Host': MY_ACCOUNT_HOST,
'Content-Type': 'text/plain; charset=UTF-8',//Added this line
'Content-MD5': corsMD5,//Added this line
};
var canonicalizedHeaders = buildCanonicalizedHeaders( headers );
// THIS
var key = buildSharedKeyLite( 'PUT', corsMD5, 'text/plain; charset=UTF-8', canonicalizedHeaders, canonicalizedResource, accountKey);
// AND THIS, BOTH YIELD THE SAME SERVER RESPONSE
// var key = buildSharedKeyLite( 'PUT', "", "", canonicalizedHeaders, canonicalizedResource, accountKey);
headers['Authorization'] = 'SharedKeyLite ' + MY_ACCOUNT_NAME + ':' + key;
var options = {
url: url,
body: MY_CORS_XML,
headers: headers
};
console.log("url : " + url);
console.log("canonicalizedResource : " + canonicalizedResource);
console.log("canonicalizedHeaders : " + canonicalizedHeaders);
console.log("corsMD5 : " + corsMD5);
console.log("key : " + key);
console.log("options : " + JSON.stringify(options));
function onPropertiesSet(error, response, body) {
if (!error && response.statusCode == 202) {
console.log("CORS: OK");
}
else {
console.log("CORS: " + response.statusCode);
console.log("body : " + body);
}
}
request.put(options, onPropertiesSet); // require('request')
};
function buildCanonicalizedHeaders( headers ) {
var xmsHeaders = [];
var canHeaders = "";
for ( var name in headers ) {
if ( name.indexOf('x-ms-') == 0 ) {
xmsHeaders.push( name );
}
}
xmsHeaders.sort();
for ( var i = 0; i < xmsHeaders.length; i++ ) {
name = xmsHeaders[i];
canHeaders = canHeaders + name.toLowerCase().trim() + ':' + headers[name] + '\n';
}
return canHeaders;
}
function buildSharedKeyLite( verb, contentMD5, contentType, canonicalizedHeaders, canonicalizedResource, accountKey) {
var stringToSign = verb + "\n" +
contentMD5 + "\n" +
contentType + "\n" +
"" + "\n" + // date is to be empty because we use x-ms-date
canonicalizedHeaders +
canonicalizedResource;
// return crypto.createHmac('sha256', accountKey).update(encodeURIComponent(stringToSign)).digest('base64');
return crypto.createHmac('sha256', new Buffer(accountKey, 'base64')).update(stringToSign).digest('base64');
}