AuthClient
Yii官方写的第三方登录扩展,可以封装了基于OpenId,OAuth1,OAuth2标准的第三方授权登录过程,可以轻松实现Facebook,GitHub,Google,LinkedIn等第三方登录集成。无奈官方自带的几个第三方(Facebook,Google)等在天朝基本没有意义,基本上只有借鉴学习的作用了。不过按照AuthClient的预定义接口,可以轻松实现微信的OAuth登陆。
WeChat OAuth2
AuthClient的每个第三方登陆实现,都是通过扩展OAuth2这个类实现。先看下第一个函数:
OAuth2.php
/**
* Composes user authorization URL.
* @param array $params additional auth GET params.
* @return string authorization URL.
*/
public function buildAuthUrl(array $params = [])
{
$defaultParams = [
'client_id' => $this->clientId,
'response_type' => 'code',
'redirect_uri' => $this->getReturnUrl(),
'xoauth_displayname' => Yii::$app->name,
];
if (!empty($this->scope)) {
$defaultParams['scope'] = $this->scope;
}
return $this->composeUrl($this->authUrl, array_merge($defaultParams, $params));
}
用于构建发起OAuth授权的URL,由于微信的请求URL要求带有'#wechat_redirect',而这个函数实现没有为这个额外的字符串预留位置,因此,需要重载这个函数:
//WeChat.php
public function buildAuthUrl(array $params = [])
{
$defaultParams = [
'appid' => $this->clientId,
'redirect_uri' => $this->getReturnUrl(),
'response_type'=>'code',
'scope'=>$this->scope,
'state'=>base64_encode(\Yii::$app->user->returnUrl)
];
$url = $this->composeUrl($this->authUrl, array_merge($defaultParams, $params));
return $url . '#wechat_redirect';
}
注意,基类用的是client_id,而微信要求的是appid,需要在重载的函数里改成appid
第二个函数是fetchAccessToken,同样的,需要重载,这里只给出重载后的代码:
//WeChat.php
public function fetchAccessToken($authCode, array $params = [])
{
$defaultParams = [
'appid' => $this->clientId,
'secret' => $this->clientSecret,
'code' => $authCode,
'grant_type' => 'authorization_code',
'redirect_uri' => $this->getReturnUrl(),
];
$response = $this->sendRequest('GET', $this->tokenUrl, array_merge($defaultParams, $params));
$token = null;
if(isset($response['access_token']))
{
$arr['oauth_token_secret'] = $this->clientSecret;
$token = $this->createToken(['params' => array_merge($arr,$response),'class'=>WeChatToken::className()]);
$this->setAccessToken($token);
}
return $token;
}
第三个需要重载的函数是apiInternal,该函数在BaseOAuth基类的中被调用,用于获取授权后的用户信息。同样的原因,需要重载如下:
protected function apiInternal($accessToken, $url, $method, array $params, array $headers)
{
/** @var $accessToken WeChatToken */
$params['access_token'] = $accessToken->getToken();
$params['openid'] = $accessToken->getOpenID();
$params['lang'] = 'zh_CN';
return $this->sendRequest($method, $url, $params, $headers);
}
自此,首次授权是没问题了,再完善下刷新token的接口吧:
public function refreshAccessToken(OAuthToken $token)
{
/**
* @var $token WeChatToken
*/
$params = [
'appid' => $this->clientId,
'refresh_token' => $token->getRefreshToken(),
'grant_type' => 'refresh_token'
];
$response = $this->sendRequest('GET', $this->refreshTokenUrl, $params);
$token = null;
if(isset($response['access_token']))
{
$arr['oauth_token_secret'] = $this->clientSecret;
$token = $this->createToken(['params' => array_merge($arr,$response),'class'=>WeChatToken::className()]);
$this->setAccessToken($token);
}
return $token;
}
如果使用的是yii2-user的扩展,还有一些额外的接口需要实现,具体查看ClientInterface接口。