PHP版 百度智能小程序第三方平台(TP)接入授权流程

百度官方授权接入文档地址:授权流程
下图是授权流程:
third.png

前期准备:在百度第三方平台申请资质,填写相关信息,包括安全域名、IP白名单,相关授权及事件接收URL。

第一步:接收ticket并保存,第三方平台(TP)申请通过后,百度小程序官方会每十分钟向指定URL推送加密ticket,我们需要做好接收、解密、保存工作

解密库参见:第三方平台消息加解密
define('LOGPATH', dirname(__FILE__));
require './aes.class.php';  // 加密解密库
require './config.class.php'; // 配置读取库
require './functions.php'; // 公用方法

// 接收推送的加密数据流
$encryptMsg = file_get_contents('php://input');
// 立即返回字符串success
echo 'success';

$data = json_decode($encryptMsg, true); // 返回数组数据

// 解密获取ticket
$tp_config = Config::get('tp_config', true);
$dataCoder = new AesEncryptUtil($tp_config['client_id'], $tp_config['aes_key']);
$decrypt_data = $dataCoder->decrypt($data['Encrypt']);
$decrypt_data = json_decode($decrypt_data, true);
$ticket = $decrypt_data['Ticket'];
logResult('/msgmsg.log', 'Ticket: ' . $ticket);

// 保存ticket到config文件
if (array_key_exists('Ticket', $decrypt_data)) :
    $file_handle = './config.php';
    if ($fp = file_get_contents($file_handle)) {
        $fp = preg_replace("/'ticket' =>.*,/", "'ticket' => '$ticket',", $fp);
        if (!file_put_contents($file_handle, $fp)) {
            logResult('/error.log', '保存ticket到config.php文件失败');
        }
    } else {
        logResult('/error.log', 'config.php文件打开失败');
    }
endif;

第二步:通过ticket获取第三方平台自己的access_token,由于存在有效期(避免请求次数过多,但目前暂无次数限制),所以同样需要保存,便于后期重复使用。

if (!defined(LOGPATH)) define('LOGPATH', dirname(__FILE__));
// 由于tp的access_token会多次用到,我把获取过程写入函数(在functions.php文件中)
function get_tp_access_token() {
    // 读取(或重新请求)第三方平台 access_token
    $cur_time = time();
    $tp_token = Config::get("tp_token", true);
    if ((int)$tp_token['created_time'] + (int)$tp_token['expires_in'] > $cur_time) {
        // 在有效期
        $tp_access_token = $tp_token['access_token'];
    } else {
        // 已过期,重新获取
        $ticket = Config::get('ticket');
        $tp_config = Config::get('tp_config', true);
        $get_token_url = "https://openapi.baidu.com/public/2.0/smartapp/auth/tp/token?client_id={$tp_config['client_key']}&ticket={$ticket}";
        $tptoken_result = sendRequest($get_token_url);
        $tptoken_result = json_decode($tptoken_result, true);
        if ($tptoken_result['errno'] == 0) {
            $tp_access_token = $tptoken_result['data']['access_token'];
            
            // 保存tp access_token到config文件
            $file_handle = './config.php';
            if ($fp = file_get_contents($file_handle)) {
                $fp = preg_replace(
                    array("/'access_token' =>.*,/", "/'expires_in' =>.*,/", "/'created_time' =>.*'/"),
                    array("'access_token' => '{$tp_access_token}',", "'expires_in' => '{$tptoken_result['data']['expires_in']}',", "'created_time' => '{$cur_time}'"),
                    $fp);
                if (!file_put_contents($file_handle, $fp)) {
                    logResult('/error.log', '保存tp access_token到config.php文件失败');
                }
            } else {
                logResult('/error.log', 'config.php文件打开失败');
            }
        } else {
            logResult('/error.log', $tptoken_result['msg']);
        }
    }
    
    return $tp_access_token;
}

// 该文件中另外两个函数是sendRequest和logResult,如下

// 日志保存
function logResult($path, $data){
    file_put_contents(LOGPATH . $path, '[' . date('Y-m-d H:i:s',time()) . '] ' . $data . "\n", FILE_APPEND);
}

// 发送http(s)请求
function sendRequest($url, $data = null){
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);

    if (!empty($data)) {
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    }
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    $output = curl_exec($curl);
    curl_close($curl);
    return $output;
}

第三步和第四步:获取预授权码pre_auth_code,并引导小程序管理员对第三方平台进行授权

// 实际使用中,直接访问该URL,获取到授权链接,小程序管理员点击后即可看到授权二维码,用手百APP扫码后完成授权过程,并返回回调页面
define('LOGPATH', dirname(__FILE__));
require './config.class.php';
require './functions.php';

// 读取(或重新请求)第三方平台 access_token
$tp_config = Config::get('tp_config', true);
$tp_access_token = get_tp_access_token();

// 获取预授权码,并生成授权链接
$get_pre_auth_code_url = "https://openapi.baidu.com/rest/2.0/smartapp/tp/createpreauthcode?access_token={$tp_access_token}";
$res_pre_auth_code = sendRequest($get_pre_auth_code_url);
$res_pre_auth_code = json_decode($res_pre_auth_code, true);
if ($res_pre_auth_code['errno'] == 0) {
    $pre_auth_code = $res_pre_auth_code['data']['pre_auth_code'];
} else {
    logResult('/error.log', $res_pre_auth_code['msg']);
}

echo '<a href="https://smartprogram.baidu.com/developer/tpservice.html?client_id=' . $tp_config['client_key'] . '&redirect_uri=https://miniapi.eiewz.cn/smartapp/granted.php&pre_auth_code=' . $pre_auth_code . '">点击进行授权</a>';

授权界面:
QQ截图20190302100127.jpg

第五步和第六步,通过回调页面获取的authorization_code和第三方平台access_token获取小程序的接口调用凭据和授权信息

此处我通过首次获取的小程序access_token,请求到小程序相关信息并保存到数据库表smartapp中
// 由于小程序的access_token在授权之后经常会用到,所以我选择保存到数据库(SQLite),字段包括:id, app_id, app_name, expires_in, create_time, refresh_token,其中,refresh_token可用来重新获取小程序access_token
define('LOGPATH', dirname(__FILE__));
require './functions.php';
require './config.class.php';
require './tp.config.php';

// 数据库信息
include_once "./ezSQL/shared/ez_sql_core.php";
include_once "./ezSQL/sqlite/ez_sql_sqlite3.php";
$db = new ezSQL_sqlite3('./','smartapp.db');

$authorization_code = $_GET['authorization_code'];
$expires_in = $_GET['expires_in'];

$tp_access_token = get_tp_access_token();

$get_access_token_url = "https://openapi.baidu.com/rest/2.0/oauth/token?access_token=$tp_access_token&code=$authorization_code&grant_type=app_to_tp_authorization_code";

$app_token_res = sendRequest($get_access_token_url);
$app_token_res = json_decode($app_token_res, true);

$cur_time = time();
$app_access_token = $app_token_res['access_token'];

$app_info_url = "https://openapi.baidu.com/rest/2.0/smartapp/app/info?access_token=$app_access_token";
$app_info = sendRequest($app_info_url);
$app_info = json_decode($app_info, true);

if ($app_info['errno'] == 0) {
    $sql = "insert into smartapp (app_id,app_name,access_token,expires_in,create_time,refresh_token) values ({$app_info['data']['app_id']},'{$app_info['data']['app_name']}','{$app_access_token}','{$app_token_res['expires_in']}','{$cur_time}','{$app_token_res['refresh_token']}')";
    
    //echo $sql;
    $db->query($sql);
    echo '授权成功';
} else {
    echo '授权失败:';
    logResult('/error.log', $app_info['msg']);
}

至此,整个授权过程完成。官方流程图第七步即通过refresh_token重新获取小程序access_token,第八步通过小程序access_token获取小程序相关信息。

ps:保存配置的文件config.php

return array(
    // ticket
    'ticket' => 'xxxxxxxxxxxxxxxxxxx',

    // tp令牌
    'tp_token' => array(
        'access_token' => 'xxxxxxxxxxx',
        'expires_in' => '2592000',
        'created_time' => '1551428362'
    ),
    
    // tp配置
    'tp_config' => array(
        'aes_key'       => 'xxxxxxxxxxxxxxxxxxxxxxx',
        'token'         => 'xxxxxxxxxx',
        'client_id'     => 'xxxxxxx',  // 第三方平台ID
        'client_key'    => 'xxxxxxxxxxxxxxxxxxx',  // 第三方平台key
        'client_secret' => 'xxxxxxxxxxxxxxxxxxxxxx'  // 第三方平台密钥
    )
);

配置读取库config.class.php

// 读取配置
class Config
{

    // 存储配置信息
    protected static $configs;

    // 直接获取配置参数
    public static function get($item = null, $array = false)
    {
        // 自动载入配置文件
        if (! isset(self::$configs)) {
            self::$configs = self::loadConfig();
        }
        // 返回全部配置
        if ($item === null) {
            return self::$configs;
        }
        $items = explode('.', $item);
        if (isset(self::$configs[$items[0]])) {
            $value = self::$configs[$items[0]];
        } else {
            return null;
        }
        $items_len = count($items);
        for ($i = 1; $i < $items_len; $i ++) {
            if (isset($value[$items[$i]])) {
                $value = $value[$items[$i]];
            } else {
                return null;
            }
        }
        // 强制返回数据为数组形式
        if ($array && ! is_array($value)) {
            if ($value) {
                $value = explode(',', $value);
                $value = array_map('trim', $value); // 去空格
            } else {
                $value = array();
            }
        }
        return $value;
    }

    // 载入配置文件
    private static function loadConfig()
    {
        // 载入用户主配置文件
        if (file_exists('config.php')) {
            $config = require 'config.php';
            $configs = self::mult_array_merge($configs, $config);
        }
        
        // 清理缓冲区,避免配置文件出现Bom时影响显示
        @ob_clean();
        return $configs;
    }
    
    // 多维数组合并
    private static function mult_array_merge($array1, $array2)
    {
        if (is_array($array2)) {
            foreach ($array2 as $key => $value) {
                if (is_array($value)) {
                    if (array_key_exists($key, $array1)) {
                        $array1[$key] = self::mult_array_merge($array1[$key], $value);
                    } else {
                        $array1[$key] = $value;
                    }
                } else {
                    $array1[$key] = $value;
                }
            }
        }
        return $array1;
    }
}

标签: PHP, 小程序, 智能小程序, 百度, 授权认证

添加新评论