Microsoft Azure и SAS для PHP

Я пытаюсь создать ссылку SAS на ресурс BLOB-объектов с помощью PHP. К сожалению, в настоящее время в Azure SDK нет способа создания подписи SAS. Я написал код для генерации SAS, но когда я пытаюсь получить ресурс по ссылке, сгенерированной этим методом, я получаю следующее сообщение: Поля подписи плохо сформированы.

    public function getSharedAccessSignatureURL($container, $blob)
{
    $signedStart = date('c', strtotime('-1 day'));
    $signedExpiry = date('c', strtotime('+1 day'));
    $signedResource = 'b';
    $signedPermission = 'r';
    $signedIdentifier = '';
    $responseContent = "file; attachment";
    $responseType = "binary";

    $canonicalizedResource = '/'.$this->account['accountName'].'/'.$container.'/'.$blob;
    $signedVersion = '2014-02-14';

    $stringToSign =
        $signedPermission."\n".
        $signedStart."\n".
        $signedExpiry."\n".
        $canonicalizedResource."\n".
        $signedIdentifier."\n".
        $signedVersion;

    $signature = base64_encode(
        hash_hmac(
            'sha256',
            urldecode(utf8_encode($stringToSign)),
            $this->account['primaryKey'],
            true
        )
    );

    $arrayToUrl = [
        'sv='.urlencode($signedVersion),
        'st='.urlencode($signedStart),
        'se='.urlencode($signedExpiry),
        'sr='.urlencode($signedResource),
        'sp='.urlencode($signedPermission),
        'rscd='.urlencode($responseContent),
        'rsct='.urlencode($responseType),
        'sig='.urlencode($signature)
    ];

    $url =  'https://'.$this->account['accountName'].'.blob.core.windows.net'.'/'
        .$container.'/'
        .$blob.'?'.implode('&', $arrayToUrl);

    return $url;
}

Любой подсказать, что я делаю не так? Я новичок в Microsoft Azure

1 ответ

Решение

Я считаю, что есть проблема с вашим $stringToSign переменная. Основываясь на документации здесь: http://msdn.microsoft.com/en-US/library/azure/dn140255.aspx, ваша строка для подписи должна быть построена следующим образом:

StringToSign = signedpermissions + "\n"
               signedstart + "\n"
               signedexpiry + "\n"
               canonicalizedresource + "\n"
               signedidentifier + "\n"
               signedversion + "\n"
               rscc + "\n"
               rscd + "\n"
               rsce + "\n"
               rscl + "\n"
               rsct

учитывая, что вы в том числе rscd а также rsct в вашей строке запросов SAS. Пожалуйста, попробуйте следующее и посмотрите, имеет ли это значение:

    $stringToSign =
            $signedPermission."\n".
            $signedStart."\n".
            $signedExpiry."\n".
            $canonicalizedResource."\n".
            $signedIdentifier."\n".
            $signedVersion."\n".
            "\n".
            $responseContent."\n".
            "\n".
            "\n".
            $responseType;

ОБНОВИТЬ

Пожалуйста, попробуйте код ниже. Замените имя учетной записи / ключ, имя контейнера и имя BLOB-объекта соответствующими значениями:

<?php
$signedStart = gmdate('Y-m-d\TH:i:s\Z', strtotime('-1 day'));
echo $signedStart."\n";
$signedExpiry = gmdate('Y-m-d\TH:i:s\Z', strtotime('+1 day'));
echo $signedExpiry."\n";
$signedResource = 'b';
$signedPermission = 'r';
$signedIdentifier = '';
$accountName = "[account name]";
$accountKey = "[account key]";
$container = "[container name]";
$blob = "[blob name]";
$canonicalizedResource = '/'.$accountName.'/'.$container.'/'.$blob;
$signedVersion = '2014-02-14';  
echo $canonicalizedResource."\n";
$rscc = '';
$rscd = 'file; attachment';//Content disposition
$rsce = '';
$rscl = '';
$rsct = 'binary';//Content type
$stringToSign = 
                $signedPermission."\n".
                $signedStart."\n".
                $signedExpiry."\n".
                $canonicalizedResource."\n".
                $signedIdentifier."\n".
                $signedVersion."\n".
                $rscc."\n".
                $rscd."\n".
                $rsce."\n".
                $rscl."\n".
                $rsct;


echo $stringToSign."\n";

$signature = base64_encode(
        hash_hmac(
            'sha256',
            $stringToSign,
            base64_decode($accountKey),
            true
        )
    );

echo $signature."\n";


$arrayToUrl = [
        'sv='.urlencode($signedVersion),
        'st='.urlencode($signedStart),
        'se='.urlencode($signedExpiry),
        'sr='.urlencode($signedResource),
        'sp='.urlencode($signedPermission),
        'rscd='.urlencode($rscd),
        'rsct='.urlencode($rsct),
        'sig='.urlencode($signature)
    ];

    $url =  'https://'.$accountName.'.blob.core.windows.net'.'/'
        .$container.'/'
        .$blob.'?'.implode('&', $arrayToUrl);

echo $url."\n";
?>

По сути, было две проблемы (кроме неправильных $stringToSign переменная):

  1. Дата начала / окончания не была правильно отформатирована.
  2. Нам нужно base64_decode ключ аккаунта для расчета подписи.

У меня точно такая же проблема. Но теперь вы можете использоватьMicrosoftAzure\Storage\Common\SharedAccessSignatureHelperкоторый может решить для вас множество проблем. Я был добавлен в общую библиотеку 2 года назад в этом PR (https://github.com/Azure/azure-storage-php/pull/73/files).

И это должно быть решено очень просто вот так:

$sasHelper = new SharedAccessSignatureHelper(
    'nameofyouraccount',
    'H...your-token...=='
);

$sas = $sasHelper->generateAccountSharedAccessSignatureToken(
    '2018-11-09',
    'rwl',
    'b',
    'sco',
    (new \DateTime())->modify('+10 minute'),
    (new \DateTime())->modify('-5 minute'),
    '',
    'https'
);

$connectionString = "BlobEndpoint=https://nameofyouraccount.blob.core.windows.net/;SharedAccessSignature={$sas}";

И у вас есть строка подключения!

Изменен и превращен в функцию от @Gaurav Mantri

function generateSasToken($bucket,$key, $accountName, $accountKey){

    $signedStart = gmdate('Y-m-d\TH:i:s\Z', time());
    $signedExpiry = gmdate('Y-m-d\TH:i:s\Z', time()+3600);
    $signedResource = 'b';
    $signedPermission = 'r';
    $signedIdentifier = '';
    $canonicalizedResource = '/' . $accountName . '/' . $bucket . '/' . $key;
    $signedVersion = '2014-02-14';
    $rscc = '';
    $rscd = 'file; attachment';//Content disposition
    $rsce = '';
    $rscl = '';
    $rsct = 'binary';//Content type

    $stringToSign =
        $signedPermission . "\n" .
        $signedStart . "\n" .
        $signedExpiry . "\n" .
        $canonicalizedResource . "\n" .
        $signedIdentifier . "\n" .
        $signedVersion . "\n" .
        $rscc . "\n" .
        $rscd . "\n" .
        $rsce . "\n" .
        $rscl . "\n" .
        $rsct;

    $signature = base64_encode(
        hash_hmac(
            'sha256',
            $stringToSign,
            base64_decode($accountKey),
            true
        )
    );

   $arrayToUrl = [
        'sv=' . urlencode($signedVersion),
        'st=' . urlencode($signedStart),
        'se=' . urlencode($signedExpiry),
        'sr=' . urlencode($signedResource),
        'sp=' . urlencode($signedPermission),
        'rscd=' . urlencode($rscd),
        'rsct=' . urlencode($rsct),
        'sig=' . urlencode($signature)
    ];

    $url = 'https://' . $accountName . '.blob.core.windows.net' . '/'
        . $bucket . '/'
        . $key . '?' . implode('&', $arrayToUrl);

    return $url;
}

Другие вопросы по тегам