Yii2 官方提供 yii2-authclient 擴展,支援 OAuth1/OAuth2/OpenID 等多種認證協議,內建 Google、Facebook、Twitter、LinkedIn、GitHub 等客戶端。本文將詳細講解如何安裝配置該擴展,並自定義 QQ 互聯客戶端實現「一鍵 QQ 登錄」功能。
composer require --prefer-dist yiisoft/yii2-authclient "*"
編輯 config/main.php,在 components 下添加 authClientCollection:
'components' => [
'authClientCollection' => [
'class' => 'yii\authclient\Collection',
'clients' => [
'google' => [
'class' => 'yii\authclient\clients\GoogleOpenId',
],
'facebook' => [
'class' => 'yii\authclient\clients\Facebook',
'clientId' => 'your_facebook_app_id',
'clientSecret' => 'your_facebook_app_secret',
],
],
],
// ...
],
修改 controllers/SiteController.php,添加 auth 動作與成功回調:
use yii\authclient\AuthAction;
class SiteController extends Controller
{
public function actions()
{
return [
'auth' => [
'class' => AuthAction::className(),
'successCallback' => [$this, 'successCallback'],
],
];
}
public function successCallback($client)
{
$attributes = $client->getUserAttributes();
// $attributes 包含:id、name、email 等用戶信息
// 此處實現:綁定本地用戶、註冊新用戶、登錄、重定向等邏輯
}
}
= yii\authclient\widgets\AuthChoice::widget([
'baseAuthUrl' => ['site/auth'],
]) ?>
QQ 互聯的 OAuth2 實現與標準流程有細微差異:
access_token 後,需先調用 oauth2.0/me 獲取 openid。openid 與 oauth_consumer_key(即 AppID)調用 user/get_user_info 獲取用戶資料。callback(...) 中),非標準 JSON,導致框架默認解析失敗。創建 common/components/QqOAuth.php:
scope === null) {
$this->scope = implode(',', ['get_user_info']);
}
}
protected function initUserAttributes()
{
// 1. 獲取 openid
$openid = $this->api('oauth2.0/me', 'GET');
// 2. 獲取用戶信息
$qquser = $this->api("user/get_user_info", 'GET', [
'oauth_consumer_key' => $openid['client_id'],
'openid' => $openid['openid'],
]);
$qquser['openid'] = $openid['openid'];
return $qquser;
}
protected function defaultName() { return 'qq'; }
protected function defaultTitle() { return 'QQ'; }
/**
* 重寫響應解析,處理 QQ 返回的 JSONP 格式
*/
protected function processResponse($rawResponse, $contentType = self::CONTENT_TYPE_AUTO)
{
if (empty($rawResponse)) return [];
switch ($contentType) {
case self::CONTENT_TYPE_AUTO:
$contentType = $this->determineContentTypeByRaw($rawResponse);
if ($contentType == self::CONTENT_TYPE_AUTO) {
// 關鍵:檢測並剝離 JSONP 回調包裹
if (strpos($rawResponse, "callback") !== false) {
$lpos = strpos($rawResponse, "(");
$rpos = strrpos($rawResponse, ")");
$rawResponse = substr($rawResponse, $lpos + 1, $rpos - $lpos - 1);
return $this->processResponse($rawResponse, self::CONTENT_TYPE_JSON);
}
throw new Exception('Unable to determine response content type automatically.');
}
return $this->processResponse($rawResponse, $contentType);
case self::CONTENT_TYPE_JSON:
$response = Json::decode($rawResponse, true);
if (isset($response['error'])) {
throw new Exception('Response error: ' . $response['error']);
}
return $response;
case self::CONTENT_TYPE_URLENCODED:
$response = [];
parse_str($rawResponse, $response);
return $response;
case self::CONTENT_TYPE_XML:
return $this->convertXmlToArray($rawResponse);
default:
throw new Exception('Unknown response type "' . $contentType . '".');
}
}
}
在 config/main.php 中添加:
'components' => [
'authClientCollection' => [
'class' => 'yii\authclient\Collection',
'clients' => [
'qq' => [
'class' => 'common\components\QqOAuth',
'clientId' => 'your_qq_app_id',
'clientSecret' => 'your_qq_app_key',
],
],
],
],
使用 QQ 快速登錄
public function successCallback($client)
{
$attributes = $client->getUserAttributes();
if ($client->id === 'qq') {
// QQ 專屬邏輯:$attributes['openid']、$attributes['nickname']、$attributes['figureurl_qq_2'] 等
} elseif ($client->id === 'facebook') {
// Facebook 邏輯
}
// 統一處理:綁定/註冊/登錄
}
Yii2 的 authclient 架構清晰,擴展性強。接入 QQ 互聯的關鍵在於:理解其非標準 OAuth2 流程(需兩步獲取用戶信息)、處理 JSONP 響應格式。通過繼承 OAuth2 並重寫 initUserAttributes() 與 processResponse(),即可優雅地納入框架統一認證體系。