App 專案要求實現第三方 微信 和 支付寶 登入,微信可以直接在 App 端完成認證拿到使用者資訊,支付寶則需要後端獲取。
- 服務端先拿到 App端 呼叫 支付寶SDK 所需要的 infoStr
- App端 通過
infoStr
獲得使用者 授權code - 服務端通過 授權code 拿到請求 token
- 服務端通過 token 獲得使用者資訊
在這之前,支付寶介面對接流程你應該有所瞭解。
-
建立 RSA2 方法:獲得
sign
:/** * enRSA2 RSA加密 * * @param String $data * @return String */ private function enRSA2($data) { $str = chunk_split(trim($this->private_key), 64, "\n"); $key = "-----BEGIN RSA PRIVATE KEY-----\n$str-----END RSA PRIVATE KEY-----\n"; // $key = file_get_contents(storage_path('rsa_private_key.pem')); 為檔案時這樣引入 $signature = ''; $signature = openssl_sign($data, $signature, $key, OPENSSL_ALGO_SHA256)?base64_encode($signature):NULL; return $signature; }
-
建立一個 Get 引數拼接方法,保證符合支付寶加簽字串要求:
/** * myHttpBuildQuery * 之所以不用 自帶函式 `http_build_query` * 是因為格式化的時間帶有 ‘:’ 會被轉換成十六進位制 utf-8 碼 * * @param Array * @return String */ private function myHttpBuildQuery($dataArr) { ksort($dataArr); $signStr = ''; foreach ($dataArr as $key => $val) { if (empty($signStr)) { $signStr = $key.'='.$val; } else { $signStr .= '&'.$key.'='.$val; } } return $signStr; }
-
給到APP端需要的
infoStr
:/** * InfoStr APP登入需要的的infostr * * @return String */ public function infoStr() { $infoStr = http_build_query([ 'apiname' => 'com.alipay.account.auth', 'method' => 'alipay.open.auth.sdk.code.get', 'app_id' => $this->app_id, 'app_name' => 'mc', 'biz_type' => 'openservice', 'pid' => $this->pid, 'product_id' => 'APP_FAST_LOGIN', 'scope' => 'kuaijie', 'target_id' => mt_rand(999, 99999), //商戶標識該次使用者授權請求的ID,該值在商戶端應保持唯一 'auth_type' => 'AUTHACCOUNT', // AUTHACCOUNT代表授權;LOGIN代表登入 'sign_type' => 'RSA2', ]); $infoStr .= '&sign='.$this->enRSA2($infoStr); return $infoStr; }
-
拿到使用者資訊:
/**
* AlipayToken 獲得使用者 請求token, 通過它獲得 使用者資訊
*
* 需要按照支付寶加簽流程來。
*/
public function userInfo($app_auth_token)
{
$infoArr = [
'method' => 'alipay.system.oauth.token',
'app_id' => $this->app_id,
'charset' => 'utf-8',
'sign_type' => 'RSA2',
'timestamp' => date('Y-m-d H:i:s'),
'version' => '1.0',
'code' => $app_auth_token,
'grant_type' => 'authorization_code',
];
$signStr = $this->myHttpBuildQuery($infoArr);
$sign = urlencode($this->enRSA2($signStr));
$qureStr = $signStr.'&sign='.$sign;
$res = new Client();
$body = $res->get('https://openapi.alipay.com/gateway.do?'.$qureStr)->getBody()->getContents();
$body = json_decode($body);
if (!isset($body->alipay_system_oauth_token_response->access_token)) {
return '介面異常';
} else {
$autho_token = $body->alipay_system_oauth_token_response->access_token;
$userinfo = $this->aliPayUserInfo($autho_token);
return $userinfo; // 或則 返回 json_encode($userinfo) 根據實際需求來
}
}
/**
* AliPayUserInfo 通過 token 獲取使用者資訊
*/
private function aliPayUserInfo($autho_token)
{
$infoArr = [
'method' => 'alipay.user.info.share',
'app_id' => $this->app_id,
'charset' => 'utf-8',
'sign_type' => 'RSA2',
'timestamp' => date('Y-m-d H:i:s'),
'version' => '1.0',
'auth_token' => $autho_token,
];
$signStr = $this->myHttpBuildQuery($infoArr);
$sign = urlencode($this->enRSA2($signStr));
$qureStr = $signStr.'&sign='.$sign;
$res = new Client();
$body = $res->get('https://openapi.alipay.com/gateway.do?'.$qureStr)->getBody()->getContents();
$body = json_decode($body);
if (!isset($body->alipay_user_info_share_response)) {
return '介面異常';
}
$body = $body->alipay_user_info_share_response;
return $body;
}
<?php
// 使用 Guzzle 做請求操作
use GuzzleHttp\Client;
// 支付寶APP 第三方登入
// 特點:相比微信,支付寶所有敏感資訊都在服務端完成, 保證了安全
//
// 流程:
// 1.服務端到APP infoStr
// 2.APP端 通過infoStr 獲得 auth_code
// 3.服務端通過 auth_code 拿到請求 token
// 4.服務端通過 token 獲得使用者資訊
class AliPayUser{
protected $app_id = '支付寶app_id';
protected $pid = '支付寶pid';
protected $private_key = '你的私鑰';
/**
* InfoStr APP登入需要的的infostr
*
* @return String
*/
public function infoStr()
{
$infoStr = http_build_query([
'apiname' => 'com.alipay.account.auth',
'method' => 'alipay.open.auth.sdk.code.get',
'app_id' => $this->app_id,
'app_name' => 'mc',
'biz_type' => 'openservice',
'pid' => $this->pid,
'product_id' => 'APP_FAST_LOGIN',
'scope' => 'kuaijie',
'target_id' => mt_rand(999, 99999), //商戶標識該次使用者授權請求的ID,該值在商戶端應保持唯一
'auth_type' => 'AUTHACCOUNT', // AUTHACCOUNT代表授權;LOGIN代表登入
'sign_type' => 'RSA2',
]);
$infoStr .= '&sign='.$this->enRSA2($infoStr);
return $infoStr;
}
/**
* AlipayToken 獲得使用者 請求token, 通過它獲得 使用者資訊
*
* 需要按照支付寶加簽流程來。
*/
public function userInfo($app_auth_token)
{
$infoArr = [
'method' => 'alipay.system.oauth.token',
'app_id' => $this->app_id,
'charset' => 'utf-8',
'sign_type' => 'RSA2',
'timestamp' => date('Y-m-d H:i:s'),
'version' => '1.0',
'code' => $app_auth_token,
'grant_type' => 'authorization_code',
];
$signStr = $this->myHttpBuildQuery($infoArr);
$sign = urlencode($this->enRSA2($signStr));
$qureStr = $signStr.'&sign='.$sign;
$res = new Client();
$body = $res->get('https://openapi.alipay.com/gateway.do?'.$qureStr)->getBody()->getContents();
$body = json_decode($body);
if (!isset($body->alipay_system_oauth_token_response->access_token)) {
return '介面異常';
} else {
$autho_token = $body->alipay_system_oauth_token_response->access_token;
$userinfo = $this->aliPayUserInfo($autho_token);
return $userinfo; // 或則 返回 json_encode($userinfo) 根據實際需求來
}
}
/**
* AliPayUserInfo 通過 token 獲取使用者資訊
*/
private function aliPayUserInfo($autho_token)
{
$infoArr = [
'method' => 'alipay.user.info.share',
'app_id' => $this->app_id,
'charset' => 'utf-8',
'sign_type' => 'RSA2',
'timestamp' => date('Y-m-d H:i:s'),
'version' => '1.0',
'auth_token' => $autho_token,
];
$signStr = $this->myHttpBuildQuery($infoArr);
$sign = urlencode($this->enRSA2($signStr));
$qureStr = $signStr.'&sign='.$sign;
$res = new Client();
$body = $res->get('https://openapi.alipay.com/gateway.do?'.$qureStr)->getBody()->getContents();
$body = json_decode($body);
if (!isset($body->alipay_user_info_share_response)) {
return '介面異常';
}
$body = $body->alipay_user_info_share_response;
return $body;
}
/**
* enRSA2 RSA加密
*
* @param String $data
* @return String
*/
private function enRSA2($data)
{
$str = chunk_split(trim($this->private_key), 64, "\n");
$key = "-----BEGIN RSA PRIVATE KEY-----\n$str-----END RSA PRIVATE KEY-----\n";
// $key = file_get_contents(storage_path('rsa_private_key.pem')); 為檔案時這樣引入
$signature = '';
$signature = openssl_sign($data, $signature, $key, OPENSSL_ALGO_SHA256)?base64_encode($signature):NULL;
return $signature;
}
/**
* myHttpBuildQuery 返回一個 http Get 傳引數組
* 之所以不用 自帶函式 http_build_query 時間帶 ‘:’ 會被轉換
*
* @param Array
* @return String
*/
private function myHttpBuildQuery($dataArr)
{
ksort($dataArr);
$signStr = '';
foreach ($dataArr as $key => $val) {
if (empty($signStr)) {
$signStr = $key.'='.$val;
} else {
$signStr .= '&'.$key.'='.$val;
}
}
return $signStr;
}
}
- 注意:這份程式碼是從原有專案扒出來,主要是為有此需求的開發人員提供參考,並未測試是否能直接使用,請自行測試。
- 之所以不用支付寶
php_SDK
,是因為需求有限:只獲取使用者的資訊,沒必要。 - 程式碼有不合理的地方還請提出來,大家互相學習。