【问题标题】:windows azure : set blob CORS properties using NodeJSwindows azure:使用 NodeJS 设置 blob CORS 属性
【发布时间】:2014-04-12 18:29:33
【问题描述】:

REST API 已于 2 月发布,用于设置 blob CORS property,但尚未针对 NodeJS 实现。

因为我需要这个功能,所以我尝试在一个运行 NodeJS 的天蓝色网站的模块中实现它。

基于 REST API 文档 to change CORS propertiesgenerate 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,2014 年 3 月 9 日 12:33:41 GMT x-ms-版本:2013-08-15 corsMD5 : +ij...w== 关键: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","headers":{"x-ms-version":"2013-08-15","x-ms-date":"Sun, 09 Mar 2014 12:格林威治标准时间 33:41","主机":"NAME_OF_MY_STORAGE_ACCOUNT.blob.core.windows.net","授权":"SharedKeyLite NAME_OF_MY_STORAGE_ACCOUNT:sNB...rY="}} CORS:403 正文: AuthenticationFailedServer 未能验证请求。确保 Authorization 标头的值正确形成,包括签名。 请求ID:1e6abfe3-e0e8-4b9c-922d-7cb34485eec9 时间:2014-03-09T12:33:41.7262308Z 在 HTTP 请求 'sNB...JrY=' 中找到的 MAC 签名与任何计算的签名都不相同。服务器使用以下字符串进行签名:'PUT

x-ms-date:2014 年 3 月 9 日星期日 12:33:41 GMT x-ms-版本:2013-08-15 /NAME_OF_MY_STORAGE_ACCOUNT/?comp=properties'。

知道我在这里做错了什么吗?感谢您的帮助

【问题讨论】:

    标签: node.js azure blob cors azure-blob-storage


    【解决方案1】:

    请在您的headers 数组中添加Content-TypeContent-MD5,这样就可以了。这是修改后的代码:

    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');
    }
    

    【讨论】:

    • 非常感谢高拉夫!它解决了服务器端的问题!所以现在,多亏了你,我可以更改我的 blob cors 属性。但我的客户端应用程序仍然无法访问它
    • 尝试将文件推送到 blob 时出现以下错误:OPTIONS MYSTORAGEACCOUNT.blob.core.windows.net/publicblobssas/……cdbLaTjhlHGag0L3slFVJbXgMFXlWnfXmsU%3D&comp=block&blockid=YmxvY2stMDAwMDAw 403(服务器无法验证请求。确保授权的值标头的格式正确,包括签名。)
    • OPTIONS MYSTORAGEACCOUNT.blob.core.windows.net/publicblobssas/…...XlWnfXmsU%3D&comp=block&blockid=YmxvDAw 请求的资源上不存在“Access-Control-Allow-Origin”标头。因此不允许访问 Origin 'fileuploaderblob.azurewebsites.net'。
    • XMLHttpRequest 无法加载 MYSTORAGEACCOUNT.blob.core.windows.net/publicblobssas/…...cXmsU%3D&comp=block&blockid=Ymxvst。请求的资源上不存在“Access-Control-Allow-Origin”标头。 Origin 'fileuploaderblob.azurewebsites.net' 因此不允许访问。
    • 这里是我为来自服务器的每个答案使用的标题:app.all('', function(req, res, next) { res.header("Access-Control-Allow -Origin", ""); res.header("Access-Control-Allow-Headers", 'x-ms-*'); res.header("Access-Control-Allow-Methods", "获取、放置、发布、删除、选项"); 下一个(); });你知道出了什么问题吗?
    【解决方案2】:

    要配置 CORS,请使用适用于 Node.js 的 Azure 存储库。

    您可以通过npm install azure-storage 获取它。源代码在https://github.com/Azure/azure-storage-node

    npm 包azure(又名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);
    

    【讨论】:

    • 谢谢,这太棒了.. 为了完整起见,该方法被称为:service.setServiceProperties(serviceProperties, callback); where serviceProperties = {Cors: {CorsRule: [{AllowedOrigins: [*], ...}]}};有关上面“...”所示所需属性的更多详细信息,请参阅:msdn.microsoft.com/library/azure/hh452235.aspx
    • 你能补充完整的答案吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-22
    • 2016-08-01
    • 2015-04-20
    • 2021-04-20
    • 1970-01-01
    • 2012-06-21
    相关资源
    最近更新 更多