原创

V3手动鉴权失败之PHP篇

导语

该系列其他篇章:

V3手动鉴权失败之Nodejs篇

V3手动鉴权失败之Go篇

V3手动鉴权失败之Python篇

V3手动鉴权失败之Java篇

V3手动鉴权失败之C#篇

腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接口级注释,让您更加方便快捷的使用腾讯云产品。人脸识别文字识别语音识别等众多产品均已接入云API 3.0。

腾讯云API为了更好的让用户接入,已经封装好了多种语言的SDK,只需用户传入SecrectId、SectectKey以及接口入参,即可完成接口鉴权和请求发送,具体包括Python SDKJava SDKPHP SDKGo SDKNodeJS SDK.NET SDK

案例背景

在某些情况,用户需要实现手动接口鉴权,虽然官网文档已有详细的接口鉴权流程,但是由于:

1.V3手动鉴权步骤较为复杂;

2.官网某些demo代码无法直接下载运行,仍需简单调整;

3.官网文档的demo代码覆盖面有限,没有包括全量上述六类后端语言;

基于此,很多用户只能自己尝试手动鉴权,但都返回“鉴权失败”,从而无法调通接口。

原因分析

从宏观上看,“鉴权失败”要关注两个阶段:

1. 整体的接口鉴权是否正确;

2. 模拟的鉴权请求的发送是否正确;

从历史问题回顾,有客户曾经出现接口鉴权时而成功,时而失败的情况,排查了整体的鉴权过程,完全正确,但是也的确复现了客户的问题。后来发现,用户在鉴权完成后,发送具体的请求时,传入的时间戳timestamp没有实时更新导致了报错。

解决方案

为了帮助客户更简单、更快捷地完成接口手动鉴权,并成功发送鉴权请求,将通过一系列文章专门讲解各个后端语言的手动鉴权&发送请求的可执行demo代码,助力客户快速接入。

本期将以调用人脸识别的DetectFace接口为例,详叙PHP语言demo。

前期准备

PHP集成开发环境:笔者使用wamp集成环境,在sourceforge中下载并安装即可。安装后,双击wampserver64启动服务。

SecrectId和SecretKey:接口鉴权的密钥。可以把SecretId理解成“账号”,把SecretKey理解成“密码”。在自己的腾讯云官网控制台获取:访问管理 -> 访问密钥 -> API密钥管理。

手动鉴权相关文档:请求结构公共参数V3接口鉴权

具体代码

运行php语言代码,即可完成v3鉴权,并发送http请求,收到具体的response响应。有两种运行方式:

方法一:进入wamp安装目录下,找到php.exe的目录,打开cmd控制台,执行php.exe php_v3.php,例如:

D:\ProgramInstall\wamp64\bin\php\php5.6.40>php.exe D:\Code\test\php_v3.php

方法二:进入wamp安装目录,找到www目录,将php_v3.php复制到www目录下,在浏览器访问127.0.0.1/php_v3.php即可:

本地访问php_v3.php鉴权代码

上述方法中涉及的php_v3.php代码如下,只需要简单复制,然后输入自己的SecretId和SecretKey两个字段即可:

<?php
class Face{
    const SecretId  = "xxx"; //填写自己的secretId
    const SecretKey = "xxx"; //填写自己的secretKey
    const Url       = "https://iai.tencentcloudapi.com";

    //算法
    const Algo                  = "sha256";
    //规范请求串
    const HTTPRequestMethod     = "POST";
    const CanonicalURI          = "/";
    const CanonicalQueryString  = "";
    const CanonicalHeaders      = "content-type:application/json; charset=utf-8\nhost:iai.tencentcloudapi.com\n";
    const SignedHeaders         = "content-type;host";//参与签名的头部信息

    //签名字符串
    const Algorithm             = "TC3-HMAC-SHA256";
    const Service               = "iai";
    const Stop                  = "tc3_request";

    /**
     * 人脸检测与分析
     */
    public function getFace(){
        $param = [
            //'MinFaceSize' => 20,
            'Url'    =>  "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599650382393&di=54ae4347050e54331809233159f4adaf&imgtype=0&src=http%3A%2F%2Faimg8.dlszyht.net.cn%2Fueditor%2Fimage%2F772%2F1542282%2F1525679281357881.jpg",
            'FaceModelVersion' => '3.0'
        ];
        return self::getCommonPostRequest("DetectFace", $param);
    }

    /**
     * 鉴权
     * @param string $action 方法
     * @param array  $param  参数
     * @param string $version 版本号
     * @return array
     */
    private static function getCommonPostRequest( $action, array $param = [], $version = "2018-03-01")
    {
        //时间戳
        $timeStamp  = time();
        //参数转化Json
        $paramJson  = json_encode($param);
        //规范请求串
        $hashedRequestPayload   =   self::HashEncryption($paramJson);
        $canonicalRequest       =   self::HTTPRequestMethod . "\n" .
            self::CanonicalURI . "\n" .
            self::CanonicalQueryString . "\n" .
            self::CanonicalHeaders . "\n" .
            self::SignedHeaders . "\n" .
            $hashedRequestPayload;
        //签名字符串
        $date                   =   gmdate("Y-m-d", $timeStamp);//UTC 0时区的值
        $credentialScope        =   $date . "/". self::Service . "/". self::Stop;
        $hashedCanonicalRequest =   self::HashEncryption($canonicalRequest);
        $stringToSign           =   self::Algorithm . "\n" .
            $timeStamp . "\n" .
            $credentialScope . "\n" .
            $hashedCanonicalRequest;

        //计算签名
        $secretDate             =   self::HashHmacSha256Encryption($date,   'TC3' . self::SecretKey);
        $secretService          =   self::HashHmacSha256Encryption(self::Service,   $secretDate);
        $secretSigning          =   self::HashHmacSha256Encryption(self::Stop,  $secretService);

        //签名
        $signature              =   self::HashHmacSha256Encryption($stringToSign,  $secretSigning, false);
        $authorization          =   self::Algorithm . ' ' .
            'Credential=' . self::SecretId . '/' . $credentialScope . ', ' .
            'SignedHeaders=' . self::SignedHeaders . ', ' .
            'Signature=' . $signature;

        //Header头部
        $headers = [
            "Authorization: $authorization",
            "Host: iai.tencentcloudapi.com",
            "Content-Type: application/json; charset=utf-8",
            "X-TC-Action: $action",
            "X-TC-Version: $version",
            "X-TC-Timestamp: $timeStamp",
            //"X-TC-Region: ap-chengdu"
        ];
        //请求
        $response   = self::get_curl_request(self::Url, $paramJson, self::HTTPRequestMethod, $headers);
        //解析
        if (!$response) {
            return ['code' => 0, 'codeError' => '1002', 'msg' => 'Interface request failed'];
        }
        $response = json_decode($response, true);
        if (!isset($response['Response'])) {
            return ['code' => 0, 'codeError' => '1003', 'msg' => 'Response error'];
        }
        if (isset($response['Response']['Error'])) {
            return [
                'code'          => 0
                , 'codeError'   => $response['Response']['Error']['Code']
                , 'msg'         => $response['Response']['Error']['Message']
                , 'RequestId'   => $response['Response']['RequestId']
            ];
        } else {
            return ['code' => 1, 'msg' => 'ok', 'data' => $response['Response']];
        }
    }

    private static function HashEncryption($sign){
        return strtolower(hash(self::Algo, $sign));
    }

    private static function HashHmacSha256Encryption($sign, $key, $flag = true){
        return hash_hmac(self::Algo, $sign, $key,  $flag);
    }

    /**
     * @param $url
     * @param array $param
     * @param string $mothod
     * @param array $headers
     * @param int $return_status
     * @param int $flag
     * @return array|bool|string
     */
    public static function get_curl_request($url, $param = [], $mothod = 'POST', $headers = [], $return_status = 0, $flag = 0)
    {
        $ch = curl_init();
        if (!$flag) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        }

        //内网需要开启代理
        //curl_setopt($ch, CURLOPT_PROXY, "127.0.0.1");
        //curl_setopt($ch, CURLOPT_PROXYPORT, 12639);

        curl_setopt($ch, CURLOPT_TIMEOUT, 6);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        if (strtolower($mothod) == 'post') {
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
        } else {
            $url = $url . "?" . http_build_query($param);
        }
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 2);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        $ret = curl_exec($ch);
        $code = curl_getinfo($ch);
        curl_close($ch);
        if ($return_status == "1") {
            return array($ret, $code);
        }
        return $ret;
    }
}

$model = new Face();
$data = $model->getFace();
var_dump($data);

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • V3手动鉴权失败之Nodejs篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • V3手动鉴权失败之Go篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • V3手动鉴权失败之Java篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • V3手动鉴权失败之Python篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • V3手动鉴权失败之C#篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • 【玩转腾讯云】【腾讯云语音合成】智能语音交互之语音合成篇

    语音合成(Text To Speech,TTS)满足将文本转化成拟人化语音的需求,打通人机交互闭环。 提供多种音色选择,支持自定义音量、语速,让发音更自然、更专...

    ruskin
  • 【AI接入迷你赛】腾讯云产品鉴权签名 v3

    腾讯云 API 会对每个请求进行身份验证,用户需要使用安全凭证,经过特定的步骤对请求进行签名 Signature,每个请求都需要在公共请求参数中指定该签名结果并...

    用户4299935
  • 一个简单的分布式事务系统的实现(订单系统)

    背景:公司最早的一个版本的订单管理,是通过PHP+mysql的方案去实现的,这样会有什么问题呢,假设如果放到一个实例里面,全部用一个单机事务去解决...

    芋道源码
  • etcd 备份与恢复

    etcd 是一款开源的分布式一致性键值存储,由 CoreOS 公司进行维护,详细的介绍请参考官方文档。

    田飞雨

扫码关注云+社区

领取腾讯云代金券