适用于Azure Cosmos DB的PHP REST身份验证令牌

时间:2020-07-21 18:11:46

标签: php azure rest azure-cosmosdb

我正在构建一个基于PHP的网页。我想使用REST API在AZURE Cosmos DB中存储,读取和更新数据。 第一个挑战是使用主密钥生成身份验证令牌。我使用了Microsoft文档:https://docs.microsoft.com/de-de/rest/api/cosmos-db/access-control-on-cosmosdb-resources 和邮递员收藏品*作为构建以下代码的参考。

*请参阅 https://www.youtube.com/watch?v=2ndj_-zp82Y https://github.com/MicrosoftCSA/documentdb-postman-collection

我使用了来自邮递员的控制台日志来比较每个步骤,并发现有不同的结果**,但是我不知道如何像从邮递员一样从我的PHP中获得相同的结果

** key64 PHP: WUtDMFF5VWZkZ1NsTFp5UmU5ZVBMbW9jV3ZSN ..... == key64邮递员: 60a0b443251f7604a52d9c917bd78f2e6a1c5af4790d3f67dc7dbd513d173418 ...否==最后 authstring PHP: 类型%253Dmaster%2526ver%253D1.0%2526sig%..... authstring邮递员: 类型%3Dmaster%26ver%3D1.0%26sig%3 .....

POSTMAN (JS)
// store our master key for documentdb
var mastKey = postman.getEnvironmentVariable("DocumentDBMasterKey");
console.log("mastKey = " + mastKey);

// store our date as RFC1123 format for the request
var today = new Date();
var UTCstring = today.toUTCString();
postman.setEnvironmentVariable("RFC1123time", UTCstring);

// Grab the request url
var url = request.url.trim(); 
console.log("request url = " + url);

// strip the url of the hostname up and leading slash
var strippedurl = url.replace(new RegExp('^https?://[^/]+/'),'/');
console.log ("stripped Url = " + strippedurl);

// push the parts down into an array so we can determine if the call is on a specific item
// or if it is on a resource (odd would mean a resource, even would mean an item)
var strippedparts = strippedurl.split("/");
var truestrippedcount = (strippedparts.length - 1);
console.log(truestrippedcount);

// define resourceId/Type now so we can assign based on the amount of levels
var resourceId = "";
var resType = "";

// its odd (resource request)
if (truestrippedcount % 2)
{
    console.log("odd");
    // assign resource type to the last part we found.
    resType = strippedparts[truestrippedcount];
    console.log("resType");
    console.log(resType);
    if (truestrippedcount > 1)
    {
        // now pull out the resource id by searching for the last slash and substringing to it.
        var lastPart = strippedurl.lastIndexOf("/");
        resourceId = strippedurl.substring(1,lastPart);
        console.log(resourceId);
    }
}
else // its even (item request on resource)
{
    console.log("even");
    // assign resource type to the part before the last we found (last is resource id)
    resType = strippedparts[truestrippedcount - 1];
    console.log("resType");
    // finally remove the leading slash which we used to find the resource if it was
    // only one level deep.
    strippedurl = strippedurl.substring(1);
    console.log("strippedurl");
    // assign our resourceId
    resourceId = strippedurl;
    console.log("resourceId");
    console.log(resourceId);
}

// assign our verb
var verb = request.method.toLowerCase();

// assign our RFC 1123 date
var date = UTCstring.toLowerCase();

// parse our master key out as base64 encoding
var key = CryptoJS.enc.Base64.parse(mastKey);
console.log("key = " + key);

// build up the request text for the signature so can sign it along with the key
var text = (verb || "").toLowerCase() + "\n" + 
               (resType || "").toLowerCase() + "\n" + 
               (resourceId || "") + "\n" + 
               (date || "").toLowerCase() + "\n" + 
               "" + "\n";
console.log("text = " + text);

// create the signature from build up request text
var signature = CryptoJS.HmacSHA256(text, key);
console.log("sig = " + signature);

// back to base 64 bits
var base64Bits = CryptoJS.enc.Base64.stringify(signature);
console.log("base64bits = " + base64Bits);

// format our authentication token and URI encode it.
var MasterToken = "master";
var TokenVersion = "1.0";
auth = encodeURIComponent("type=" + MasterToken + "&ver=" + TokenVersion + "&sig=" + base64Bits);
console.log("auth = " + auth);

// set our auth token enviornmental variable.
postman.setEnvironmentVariable("authToken", auth);

PHP代码

#PHP Script
function generateAuthKey($url, $method){
$key = "****************";
    $date = new DateTime('');
    $date = $date->format('D, d M Y H:i:s O');
    $ressourcetype = "";
    $strippedurl = parse_url($url, PHP_URL_PATH);
    $strippedparts = explode("/", $strippedurl);
    $strippedurlcount = sizeof($strippedparts)-1;

    #GET RESSOURCE TYPE
    if ($strippedurlcount % 2){
        $resType = $strippedparts[$strippedurlcount];
    
        if ($strippedurlcount > 1){
            $ressourcetype = $strippedparts[$strippedurlcount];
        }
    }
    else{
       $ressourcetype = $strippedparts[$strippedurlcount-1];
    }
    $sig = nl2br(strtolower($method)."\n".strtolower($ressourcetype)."\n".$strippedurl."\n".strtolower($date)."\n".""."\n");
    $sig = utf8_encode($sig);
    $key64 = base64_encode($key);
    echo $key64."\n";
    $hmac = hash_hmac('sha256',$sig,$key64);

    $token = "type=master&ver=1.0&sig=".$hmac;
    return urlencode($token);
}

如何更改PHP脚本以提供与Postman(JS)相同的输出?

1 个答案:

答案 0 :(得分:0)

我认为问题在于以下代码行:

$key64 = base64_encode($key);

根据REST API documentation,您应该对密钥进行base64_decode,因为该密钥已经通过base64编码。

请尝试将您的代码更改为:

$key64 = base64_decode($key);