本文,基於 Laravel 框架的內嵌語法,進行編碼,原生實現也是一樣,只是接收參數,讀配置文件,語法變了。
在講解支付寶、QQ、微博、Github、百度賬號等平臺的第三方登錄之前,我們有必要先了解一下,第三方登錄所使用的協議。具體的詳細內容請看我的這篇博客:
https://blog.csdn.net/weixin_43885417/article/details/91163338
開始入正題,既然知道了授權協議,下一步,肯定開始申請開發者身份,獲取請求接口的權限。
先來一個簡單的熱熱身:
一 、Github
詳細步驟:
- 首先進入 Github 官網登錄
https://github.com
等你註冊好之後,你就可以上上一個圖片顯示你的應用,點進去
然後開始進入開發環節:
在看我的代碼之前,可以看看官方文檔的接口和參數要求:
https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/ - 首先我們需要在前端頁面中添加一個登錄連接,類似這樣:
https://github.com/login/oauth/authorize?client_id=你自己 APPID&redirect_uri =你的回調地址&scope =user&state=你自己的識別字段值(github 那邊會再次返回給你,讓你判斷是不是你想要的請求)。
github 會回調你的接口地址,類似這樣。
https://blogback.zhangtengfei-steven.cn/gitHub?code=425e65d6c1e18c821683&state=上面提到的標識
你需要用 PHP 自帶的$_GET[‘code’],獲取 code,用它去獲取 access_token。 - 請求https://github.com/login/oauth/access_token,獲取access_token。需要傳 client_id, client_secret, code。
github那邊會以 URL 參數格式返回給你結果,類似這樣:
access_token=d14bec07c422b4d03b11b9954f383a292ee3dd0e&scope=user&token_type=bearer - 拿到 access_token之後,就可以獲取用戶信息了。
請求https://api.github.com/user
注意!注意!注意!:
這裏有一個坑,請求獲取用戶接口的時候,需要帶上 header 頭信息,否則會報一個錯誤,
$headers[] = 'Authorization: token '. (拼接上獲取的 access_token);
下面我上菜了:
<?php
namespace App\Http\Controllers\CommonControllers;
use App\Http\Controllers\Controller;//laravel 框架封裝好的Controller
use Illuminate\Http\Request; //laravel 框架封裝好的 Request
class GitHubLogin extends Controller
{
public function gitHubCallBack(Request $request)
{
if ($request->has('code')) {
$github_login_cg = config('github');//登錄的配置文件加載
$param = array(
'code' => $request->code,
'client_id' => $github_login_cg['client_id'],
'client_secret' => $github_login_cg['client_secret'],
);
$url = $github_login_cg['access_token_url'];
$content = getHttpResponsePOST($url, $param); //獲取access_token
$data = array();
//$content====>'A=XXXXX&B=XXXX', github以路由參數返回結果
parse_str($content,$data);//解析返回的值,賦給變量$data
//請求用戶信息
if (!empty($data['access_token'])) {
$info_url = $github_login_cg['get_user_url'] . $data['access_token'];
$token = $data['access_token'];
$headers[] = 'Authorization: token '. $token;
$headers[] = "User-Agent: 壞小哥博客";
$result = getHttpResponseGET($info_url, $headers);
$user_info = json_decode($result, true);
//接下來就是你自己的業務邏輯
..............
}
}
}
}
上面提到的 github.php配置 文件
<?php
return [
'client_id' => '你自己的client_id',
'client_secret' => '你自己的client_secrect',
'state' => 'xxxxx', //標識字段,防csrf 攻擊,github 那邊會原模原樣返回給你,返回state 不正確,我們不處理
'access_token_url' => 'https://github.com/login/oauth/access_token',//獲取toke地址
'get_user_url' => 'https://api.github.com/user?', //獲取用戶信息地址
];
下面是獲取到的信息
二、支付寶:
詳細步驟:
進入官網,先註冊賬號,然後申請開發者,進行認證。
https://open.alipay.com/platform/home.htm
然後創建一個應用
進入你的應用之後,你會看到能力列表,添加能力,獲取接口權限
我們實現第三方登錄只需有獲取會員信息和第三方應用授權這倆接口就行。
點擊應用信息
上面有APPID,還有上面圈住的都要進行配置,我們調用支付寶的接口,需要傳我們的私鑰,然後支付寶那邊會回調我們配置的回調接口。
接下來就是開發流程:
支付寶獲取用戶信息的開發文檔:https://opendocs.alipay.com/open/284/web
- 首先,我們需要前臺點擊支付寶登錄按鈕,請求支付寶授權
URL:https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?app_id=APPID&scope=SCOPE&redirect_uri=你的回調地址,地址要和支付寶平臺配置一致
之後,支付寶會跳轉到你配置的回調地址,類似這樣:
http://example.com/doc/toAuthPage.html?app_id=2014101500013658&source=alipay_wallet&scope=auth_user&auth_code=ca34ea491e7146cc87d25fca24c4cD11
你可以通過PHP全局變量$_GET[‘auth_code’],獲取auth_code。 - 拿auth_code換access_token
auth_code、app_id(你的應用ID)、scope (接口權限值,目前只支持 auth_user 和 auth_base 兩個值)
獲取access_token,接口地址:https://opendocs.alipay.com/apis/api_9/alipay.system.oauth.token
在獲取access_token的接口中,你要傳一個sign(簽名)參數,這個參數的值,需要我們自己拼接處理。
下載生成私鑰和公鑰工具的地址:
https://opendocs.alipay.com/open/291/105971
文檔寫的很詳細,在這裏不再敘述,應該在配置應用的時候,已經下過,也進行配置了。把我們的公鑰複製到應用信息接口加簽方式裏,目的是,支付寶會根據你的公鑰進行解密你傳的加密數據(利用的是非對稱加密原理)
具體的sign(簽名生成,代碼中會解釋說明)。
根據文檔說明,進行傳參,POST請求,不出意外,我們可以得到以json形式返回的access_token信息。 - 獲取用戶信息,傳access_token,POST方式請求用戶信息接口。
注意,用戶信息數據是以gbk的編碼格式返回給你數據,需要你用php的mb_convert_encoding編碼轉換函數,轉換一下。才能解析,否則中文會亂碼的。
至此,流程講解完畢。
開始上菜:
<?php
namespace App\Http\Controllers\CommonControllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class AliPayLogin extends Controller
{
public function aliPayLoginCallBack(Request $request)
{
if (!$request->has('auth_code')) {
echo '獲取app_auth_code失敗,請重試';
exit;
}
//獲取app_auth_token
$ali_pay_login_cg = config('alipay')['login'];
$base_param = array(
'app_id' => $ali_pay_login_cg['app_id'],
'grant_type' => $ali_pay_login_cg['grant_type'],
'charset' => $ali_pay_login_cg['charset'],
'sign_type' => $ali_pay_login_cg['sign_type'],
'version' => $ali_pay_login_cg['version'],
);
$get_token_param = array_merge($base_param, array(
'method' => $ali_pay_login_cg['get_token_api'],
'code' => $request->auth_code,
'timestamp' => date('Y-m-d H:i:s')
));
$signStr = aliPayParamToString($get_token_param); //參數拼接
$rsa = enRSA2($signStr); //對拼接好的請求參數數據進行RSA加密
$sign = urlencode($rsa); //生成url格式的請求參數
$query = $signStr . '&sign=' . $sign; //請求參數
$url = $ali_pay_login_cg['base_url'] . $query;
$access_token = getHttpResponsePOST($ali_pay_login_cg['base_url'], $query);
$access_token_info = json_decode($access_token, true);
if (!isset($access_token_info['alipay_system_oauth_token_response'])) {
echo '獲取token信息失敗';
exit;
}
$access_token = $access_token_info['alipay_system_oauth_token_response']['access_token'];
//請求用戶信息
$get_info_param = array_merge($base_param, array(
'method' => $ali_pay_login_cg['user_info_api'],
'timestamp' => date('Y-m-d H:i:s'),
'auth_token' => $access_token,
));
$signStr = aliPayParamToString($get_info_param);//拼接參數
$rsaStr = enRSA2($signStr); //RSA加密
$sign = urlencode($rsaStr); //生成url格式的請求參數
$query = $signStr . '&sign=' . $sign;請求參數
$user_info = getHttpResponsePOST($ali_pay_login_cg['base_url'], $query);
$user_info = mb_convert_encoding($user_info, 'utf-8', 'gbk');//把返回結果,從gbk格式轉爲utf-8格式
$user_info = json_decode($user_info, true); //解析json
//接下來,寫自己的業務邏輯
.........................
}
}
aliPay.php(請求配置文件)
<?php
return [
'login' => [
'app_id' => 'yourselfID', //應用ID
'format' => 'json', //要求支付寶返回的數據格式
'charset' => 'utf-8', //我們的請求參數的編碼格式
'sign_type' => 'RSA2', //簽名加密方式
'version' => '1.0', //調用接口的版本
'scope' => 'auth_user', //獲取的信息類型
'grant_type' => 'authorization_code', //獲取code需要傳,固定格式
'base_url' => 'https://openapi.alipay.com/gateway.do',//請求支付寶的基礎接口地址
'get_token_api' => 'alipay.system.oauth.token', //請求access_token的接口名
'user_info_api' => 'alipay.user.info.share' //請求用戶信息的接口名
]
];
上面提到的aliPayParamToString參數拼接方法
function aliPayParamToString($dataArr)
{
ksort($dataArr); //按鍵進行降序排序,這個必須要做
$signStr = '';
foreach ($dataArr as $key => $val) {
if (empty($signStr)) {
$signStr = $key.'='.$val;
} else {
$signStr .= '&'.$key.'='.$val;
}
}
return $signStr;
}
上面提到的enRSA2參數拼接方法
function enRSA2($data)
{
$path = public_path() . '/key/private_key.txt'; //私鑰地址
$private_key = file_get_contents($path); //讀取私鑰內容
$str = chunk_split(trim($private_key), 64, "\n"); //去除空格,並且每64個字符,加一個換行符。
$key = "-----BEGIN RSA PRIVATE KEY-----\n$str-----END RSA PRIVATE KEY-----\n";
$signature = '';
$signature = openssl_sign($data, $signature, $key, OPENSSL_ALGO_SHA256) ? base64_encode($signature) : NULL;//數據加密
return $signature;
}
上面提到的請求接口的公共方法:
getHttpResponseGET()
/**
* @param $url
* @param null $header
* @return bool|string
*/
function getHttpResponseGET($url,$header = null) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
if(!empty($header)){
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
unset($curl);
return $output;
}
getHttpResponsePOST()
/**
* 遠程獲取數據,POST模式
* @param string $url
* @param array $param
* @return bool|string
*/
function getHttpResponsePOST($url = '', $param = array()) {
if (empty($url)) {
return false;
}
$ch = curl_init(); //初始化curl
curl_setopt($ch, CURLOPT_URL,$url); //抓取指定網頁
curl_setopt($ch, CURLOPT_HEADER, false); //是否返回響應頭信息
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); //要求結果爲字符串且輸出到屏幕上
curl_setopt($ch, CURLOPT_POST, true); //post提交方式
if (!empty($param)) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); //是否將結果返回
$data = curl_exec($ch); //運行curl
if (curl_errno($ch)) {
echo 'Errno'. json_encode(curl_error($ch)); //捕抓異常
}
curl_close($ch);
return $data;
}