美文网首页
百度云API鉴权总结

百度云API鉴权总结

作者: 梅先森森森森森森 | 来源:发表于2019-09-26 16:54 被阅读0次

最近在研究百度云的一些服务,处理api接口鉴权时花了不少时间,总结一下,方便大家对接:
废话不说,直接上代码

Signer.php:签名工具类,鉴权签名的核心方法都在这里
Utils.php:封装的工具类,鉴权,返回json数据等都在这里
Account.php:示例Controller,请求百度云接口
使用的tp5框架,代码仅供参考,思路可以供大家借鉴,如有不当之处,欢迎指正

签名工具类
Signer.php

<?php

class SignerException extends Exception
{
function __construct(message) { parent::__construct(message, 999);
}
}

class Signer
{
private ak; privatesk;
private version = "1"; privatetimestamp;
private expiration = 1800; privatemethod;
private uri; privateparams = array();
private headers = array(); privateneedLog = false;

function __construct($accessKey, $secretKey)
{
    $this->ak = $accessKey;
    $this->sk = $secretKey;
    $date = new DateTime('now');
    $date->setTimezone(new DateTimeZone('UTC'));
    $this->timestamp = $date->format('Y-m-d\TH:i:s\Z');
}

public function setVersion($version)
{
    $this->version = $version;
}

public function setExpiration($expiration)
{
    $this->expiration = $expiration;
}

public function setMethod($method)
{
    if (!empty($method)) {
        $this->method = strtoupper($method);
    }
}

public function setTimestamp($timestamp)
{
    $this->timestamp = $timestamp;
}

public function setUri($uri)
{
    $this->uri = $uri;
}

public function setParams($params)
{
    $this->params = $this->normalizeParam($params);
}

public function setSignHeaders($headers)
{
    $this->headers = $this->normalizeHeaders($headers);
}

public function beLog($needLog)
{
    $this->needLog = $needLog;
}

public function genAuthorization()
{
    $signature = $this->genSignature();
    $authStr = "bce-auth-v" . $this->version . "/" .
        $this->ak . "/" . $this->timestamp . "/" .
        $this->expiration . "/" . $this->getSignedHeaderNames() . "/" . $signature;
    return $authStr;
}

public function genSignature()
{
    if (empty($this->method)) {
        throw new SignerException("method is null or empty");
    }
    $signingKey = $this->genSigningKey();
    $this->signerLog("signingKey:" . $signingKey, __LINE__, __FILE__);
    $authStr = $this->method . "\n" .
        $this->getCanonicalURI() . "\n" .
        $this->getCanonicalParam() . "\n" .
        $this->getCanonicalHeaders();
    $this->signerLog("auth str:" . $authStr, __LINE__, __FILE__);
    return $this->sha256($signingKey, $authStr);
}

public function genSigningKey()
{
    if (empty($this->ak)) {
        throw new SignerException("access key is null or empty");
    }
    if (empty($this->sk)) {
        throw new SignerException("secret key is null or empty");
    }
    if (empty($this->version)) {
        throw new SignerException("version is null or empty");
    }
    if (empty($this->timestamp)) {
        throw new SignerException("timestamp is null or empty");
    }
    if (empty($this->expiration)) {
        throw new SignerException("expiration is null or empty");
    }
    $authStr = "bce-auth-v" . $this->version . "/" . $this->ak . "/" .
        $this->timestamp . "/" . $this->expiration;
    return $this->sha256($this->sk, $authStr);
}

public function getCanonicalParam()
{
    if (empty($this->params)) {
        return "";
    }
    $arryLen = count($this->params);
    $canonicalParams = "";
    foreach ($this->params as $key => $value) {
        if (is_array($value)) {
            $num = count($value);
            if (count($value) == 0) {
                $canonicalParams = $canonicalParams . $key . "=";
            } else {
                foreach ($value as $item) {
                    $canonicalParams = $canonicalParams . $key . "=" . $item;
                    if ($num > 1) {
                        $canonicalParams = $canonicalParams . "&";
                        $num--;
                    }
                }
            }
        } else {
            $canonicalParams = $canonicalParams . $key . "=" . $value;
        }
        if ($arryLen > 1) {
            $canonicalParams = $canonicalParams . "&";
            $arryLen--;
        }
    }
    return $canonicalParams;
}

public function getCanonicalURI()
{
    if (empty($this->uri)) {
        throw new SignerException("uri is null or empty");
    }
    $newUri = $this->dataEncode($this->uri, true);
    if (strpos($newUri, "/") === 0) {
        return $newUri;
    }
    return "/" . $newUri;
}

public function getCanonicalHeaders()
{
    if (empty($this->headers) || !array_key_exists("host", $this->headers)) {
        throw new SignerException("host not in headers");
    }
    $canonicalHeaders = "";
    $strArry = array();
    foreach ($this->headers as $key => $value) {
        if (empty($value)) {
            continue;
        }
        $strArry[] = $this->dataEncode($key, false) . ":" . $value;
    }
    $arryLen = count($strArry);
    for ($i = 0; $i < $arryLen; $i++) {
        if ($i < $arryLen - 1) {
            $canonicalHeaders = $canonicalHeaders . $strArry[$i] . "\n";
            continue;
        }
        $canonicalHeaders = $canonicalHeaders . $strArry[$i];
    }
    return $canonicalHeaders;
}

private function sha256($key, $data)
{
    return hash_hmac('sha256', $data, $key);
}

private function dataEncode($data, $isPath)
{
    if (empty($data)) {
        return "";
    }
    $encode = mb_detect_encoding($data, array("ASCII", "UTF-8", "GB2312", "GBK", "BIG5"));
    if ($encode != "UTF-8") {
        $data = $code1 = mb_convert_encoding($data, 'utf-8', $encode);
    }
    $encodeStr = rawurlencode($data);
    if ($isPath) {
        $encodeStr = str_replace("%2F", "/", $encodeStr);
    }
    return $encodeStr;
}

private function normalizeHeaders($headers)
{
    $newArray = array();
    if (empty($headers)) {
        return $newArray;
    }
    foreach ($headers as $key => $value) {
        $newKey = strtolower($key);
        if (empty($newKey)) {
            continue;
        }
        $newArray[$newKey] = $this->dataEncode(trim($value), false);
    }
    ksort($newArray);
    return $newArray;
}

private function normalizeParam($params)
{
    $newArray = array();
    if (empty($params)) {
        return $newArray;
    }
    foreach ($params as $key => $value) {
        if (empty($key) || strtolower($key) == "authorization") {
            continue;
        }
        if (is_array($value)) {
            $newSubArray = array();
            foreach ($value as $item) {
                $newSubArray[] = $this->dataEncode($item, false);
            }
            sort($newSubArray);
            $newArray[$this->dataEncode($key, false)] = $newSubArray;
        } else {
            $newArray[$this->dataEncode($key, false)] = $this->dataEncode($value, false);
        }
    }
    ksort($newArray);
    return $newArray;
}

private function getSignedHeaderNames()
{
    $arryLen = count($this->headers);
    $headerNames = "";
    foreach ($this->headers as $key => $value) {
        $headerNames = $headerNames . $key;
        if ($arryLen > 1) {
            $headerNames = $headerNames . ";";
            $arryLen--;
        }
    }
    return $headerNames;
}

private function signerLog($content, $line, $file)
{
    if ($this->needLog) {
        error_log($file . ":" . $line . ":[" . $content . "]\n", 3, "./signer_log");
    }
}

}

?>

封装的工具类,集成了常用的方法
Utils.php

<?php

/**

  • Created by PhpStorm.
  • User: 王中阳
  • Date: 2019/7/24
  • Time: 9:45
    */
    require 'Signer.php';
    define('AK', "your ak");
    define('SK', "your sk");
    define('HOST', "sem.baidubce.com"); //按百度要求换内容
    define('BASE_URL', "http://sem.baidubce.com/");//按百度要求换内容
    define('HTTP_Method', "POST");//按百度要求换内容

class Utils
{
//公共header 注意:我对接的是百度信息流推广api,header应根据百度云各服务的要求进行修改
static function Header()
{
return [
'opUsername' => 'xxxxxxx',
'opPassword' => 'xxxxxxx',
'tgUsername' => 'xxxxxxx',
'tgPassword' => 'xxxxxxx',
'bceUser' => 'xxxxxxx',
];
}

//请求百度
static function curl_post($url, $body, $auth)
{
    //处理请求体
    $files = [
        'header' => self::Header(),
        'body' => $body
    ];
    $files = json_encode($files, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_URL, $url);


    curl_setopt($ch, CURLOPT_POSTFIELDS, $files);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json',
            'host:sem.baidubce.com',  //改成你的数据
            'authorization:' . $auth,
            'accept-encoding:gzip, deflate',
            'accept:*/*'
        )
    );
    $response = curl_exec($ch);
    $request = curl_getinfo($ch, CURLINFO_HEADER_OUT);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    self::result($httpCode, $response);
}

//校验权限
static function gen_auth($uri = "")
{
    $headers = array();
    $headers['host'] = HOST;
    $signer = new \Signer(AK, SK);
    $signer->setMethod(HTTP_Method);
    $signer->setUri($uri);
    $signer->setSignHeaders($headers);
    try {
        $signature = $signer->genAuthorization();
        return $signature;
    } catch (SignerException $e) {
        echo $e->getMessage();
        return;
    }
}

//返回结果
static public function result($errno = 0, $data = '')
{
    header("Content-type: application/json;charset=utf-8");

    $errno = intval($errno);

    //注意:这里可能不满足你的项目 根据百度返回结果做修改 或者不用我这种处理方式
    //json转数组
    $data = json_decode($data, true);
    if (isset($data['header']['failures'][0])) {
        $message = $data['header']['failures'][0]['message'];
    } else {
        $message = 'success';
    }

    $json = json_encode($data['body']['data'][0]);
    $result = array(
        'errno' => 1,
        'message' => $message,
        'data' => json_encode($data['body']['data'][0]),//处理百度 返回结果
    );
    echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

/**
 * 时间 日期
 */
static public function ymd($time)
{
    return date("Y-m-d", $time);
}

}
业务层controller:百度api在请求接口的同时做权限校验
Account.php

<?php
namespace app\index\controller;

require 'Utils.php';

class Account
{
/**
* 获得账号信息
*/
public function info()
{
uri = "v1/feed/cloud/AccountFeedService/getAccountFeed";auth = \Utils::gen_auth(uri);url = BASE_URL . $uri;

    $body = [
        'accountFeedFields' => [
            'userId',
            'balance',
            'budget',
            'balancePackage',
            'userStat',
            'uaStatus',
            'validFlows',
        ],
    ];
    //返回数据集成在Utils中
    \Utils::curl_post($url, $body, $auth);
}

思路仅供参考。如有更好的处理方式,欢迎赐教。

相关文章

网友评论

      本文标题:百度云API鉴权总结

      本文链接:https://www.haomeiwen.com/subject/sjrnuctx.html