总结一下,方便大家对接:
- Signer.php:签名工具类,鉴权签名的核心方法都在这里
- Utils.php:封装的工具类,鉴权,返回json数据等都在这里
- Account.php:示例Controller,请求百度云接口
使用PHP的TP5框架,代码仅供参考,思路可以供大家借鉴,如有不当之处,欢迎指正
签名工具类
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); }