最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 百度云API服务端鉴权总结

    正文概述 转载于:掘金(王中阳Go)   2021-04-25   36

    我结合自己的业务场景,选择了API鉴权的方式对接,处理API接口鉴权时花了不少时间。

    总结一下,方便大家对接:

    • Signer.php:签名工具类,鉴权签名的核心方法都在这里
    • Utils.php:封装的工具类,鉴权,返回json数据等都在这里
    • Account.php:示例Controller,请求百度云接口

    签名工具类

    Signer.php

    <?php
    
    class SignerException extends Exception
    {
        function __construct($message)
        {
            parent::__construct($message, 999);
        }
    }
    
    class Signer
    {
        private $ak;
        private $sk;
        private $version = "1";
        private $timestamp;
        private $expiration = 1800;
        private $method;
        private $uri;
        private $params = array();
        private $headers = array();
        private $needLog = 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);
        }
    

    我一直认为好的博客有2个特点:

    1. 简明扼要的讲明白方案的思路,逻辑。
    2. 完整的代码首先示例,读者只需要替换key、secret等敏感信息后,就可以很方便的在自己的项目中使用。

    我的文章就符合这2个特点。


    起源地 » 百度云API服务端鉴权总结

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元