开发流程:
1.在button 组件中,将 open-type 设置为 getPhoneNumber,并使用 bindgetphonenumber 作为获取用户手机号的回调
2.返回值中的 encryptedData 和 iv 需要发送到服务端解密,详细可参考用户数据的签名验证和加解密,代码处理包括:
- 获取session_key
- 解密
操作流程:
(1)获取session_key:参考文档:https://smartprogram.baidu.com/docs/develop/api/open/log_Session-Key。code由前端传值。
<?php
/**
* 获取sessionkey 方法
* @param string $code 由swan.login获取的临时登录凭证
* @param string $clientId 小程序appkey
* @param string $sk 小程序appSecretKey
*/
function reqGetSessionkey($code, $clientId, $sk)
{
$url = 'https://spapi.baidu.com/oauth/jscode2sessionkey';
$data = array(
"code" => $code,
"client_id" => $clientId,
"sk" => $sk
);
$ret = curlPost($url, $data);
return $ret;
}
/**
* curl POST请求工具类
*
* @param string $url
* 请求的url地址
* @param array $postDataArr
* 传递的数组参数
* @return string 检测结果json字符串
*/
function curlPost($url, $postDataArr)
{
$headerArr = array(
"Content-type:application/x-www-form-urlencoded"
);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $postDataArr);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headerArr);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
// 获取sessionkey demo
echo reqGetSessionkey("8ba01454ac57775d3692f5dbfcac7a28NW", "4fecoAqgCIUtzIyA4FAPgoyrc4oUc25c", "xxx");
返回:
{
openid: "l214zFqNrEuIEnp6m7Y01sw8yj",
session_key: "981ce8b151c0599acf7ad1a673c6ff5e"
}
(2)解密:参考文档:https://smartprogram.baidu.com/docs/develop/api/open/log_userdata。sessio_key,由后端自己获取。iv 和 ciphertext(前端变量名为encryptedData) 由前端传值。
<?php
/**
* @Author: smartprogram_rd@baidu.com
* Copyright 2018 The BAIDU. All rights reserved.
*
* 百度小程序用户信息加解密示例代码(面向过程版)
* 示例代码未做异常判断,请勿用于生产环境
*/
function test() {
$app_key = 'y2dTfnWfkx2OXttMEMWlGHoB1KzMogm7';
$session_key = '1df09d0a1677dd72b8325aec59576e0c';
$iv = "1df09d0a1677dd72b8325Q==";
$ciphertext = "OpCoJgs7RrVgaMNDixIvaCIyV2SFDBNLivgkVqtzq2GC10egsn+PKmQ/+5q+chT8xzldLUog2haTItyIkKyvzvmXonBQLIMeq54axAu9c3KG8IhpFD6+ymHocmx07ZKi7eED3t0KyIxJgRNSDkFk5RV1ZP2mSWa7ZgCXXcAbP0RsiUcvhcJfrSwlpsm0E1YJzKpYy429xrEEGvK+gfL+Cw==";
$plaintext = decrypt($ciphertext, $iv, $app_key, $session_key);
// 解密结果应该是 '{"openid":"open_id","nickname":"baidu_user","headimgurl":"url of image","sex":1}'
echo $plaintext, PHP_EOL;//PHP_EOL php换行输出
}
test();
/**
* 数据解密:低版本使用mcrypt库(PHP < 5.3.0),高版本使用openssl库(PHP >= 5.3.0)。
*
* @param string $ciphertext 待解密数据,返回的内容中的data字段
* @param string $iv 加密向量,返回的内容中的iv字段
* @param string $app_key 创建小程序时生成的app_key
* @param string $session_key 登录的code换得的
* @return string | false
*/
function decrypt($ciphertext, $iv, $app_key, $session_key) {
$session_key = base64_decode($session_key);
$iv = base64_decode($iv);
$ciphertext = base64_decode($ciphertext);
$plaintext = false;
if (function_exists("openssl_decrypt")) {
$plaintext = openssl_decrypt($ciphertext, "AES-192-CBC", $session_key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
} else {
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, null, MCRYPT_MODE_CBC, null);
mcrypt_generic_init($td, $session_key, $iv);
$plaintext = mdecrypt_generic($td, $ciphertext);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
}
if ($plaintext == false) {
return false;
}
// trim pkcs#7 padding
$pad = ord(substr($plaintext, -1));
$pad = ($pad < 1 || $pad > 32) ? 0 : $pad;
$plaintext = substr($plaintext, 0, strlen($plaintext) - $pad);
// trim header
$plaintext = substr($plaintext, 16);
// get content length
$unpack = unpack("Nlen/", substr($plaintext, 0, 4));
// get content
$content = substr($plaintext, 4, $unpack['len']);
// get app_key
$app_key_decode = substr($plaintext, $unpack['len'] + 4);
return $app_key == $app_key_decode ? $content : false;
}
Notice:
1、session_key是具有时效性的,过期的 session_key 将无法使用。开发者在 session_key 失效时,需要通过重新执行登录流程获取有效的 session_key 。无需缓存session_key
2、 使用checkSession()可以校验 Session Key 是否有效,从而避免小程序反复执行登录流程,参考授权流程图中 checkSession() 使用。
3、 智能小程序不会把 session_key 的有效期告知开发者。我们会根据用户使用小程序的行为对 session_key 进行续期。用户越频繁使用小程序, session_key 有效期越长。
4、session_key 过期会导致开放数据解密失败。要判断当前用户的授权会话是否仍处于有效期,可调用swan.checkSession()方法进行判断,详情参照授权登录流程说明。