??Socialite社會(huì)化認(rèn)證(第三方登入)支持QQ/微信/微博/抖音/支付寶/淘寶等20幾種

webman-socialite
webman-socialite 是一個(gè) OAuth2 社會(huì)化認(rèn)證工具。 它借鑒于 laravel/socialite ,你可以輕易的運(yùn)行在webman的laravel/tp/yii等項(xiàng)目中使用它
該工具現(xiàn)已支持平臺(tái)有:Facebook,Github,Google,Linkedin,Outlook,QQ,TAPD,支付寶,淘寶,百度,釘釘,微博,微信,抖音,飛書(shū),Lark,豆瓣,企業(yè)微信,騰訊云,Line,Gitee,Coding。
如果你覺(jué)得方便了你,可以為我點(diǎn)個(gè)小星星點(diǎn)擊這里 :heart:
安裝
composer require shopwwi/webman-socialite
配置
在使用 Socialite
之前,您還需要為應(yīng)用程序使用的 OAuth
服務(wù)添加憑據(jù)。 這些憑證應(yīng)該放在你的 config/plugin/shopwwi/socialite/app.php
配置文件中,并且應(yīng)該使用密鑰 facebook,twitter,linkedin,google,github,gitlab 或 bitbucket, 取決于您的應(yīng)用程序所需的提供商。 例如:
'driver' => [
...
'qq' => [
'provider' => \Shopwwi\WebmanSocialite\Providers\QqProvider::class,
'client_id' => '',
'client_secret' => '',
'redirect' => 'http://your-callback-url',
],
...
]
使用方法
接下來(lái),就要對(duì)用戶認(rèn)證了!這需要兩個(gè)路由:一個(gè)路由用于把用戶重定向到 OAuth provider,另一個(gè)則用于在認(rèn)證完成后接收相應(yīng) provider
的回調(diào)請(qǐng)求??梢酝ㄟ^(guò) Socialite facade
的方式來(lái)訪問(wèn) Socialite:
<?php
namespace app\controller\auth;
use support\Request;
use Shopwwi\WebmanSocialite\Facade\Socialite;
class QqController
{
/**
* 將用戶重定向到 QQ 的授權(quán)頁(yè)面
*
* @return
*/
public function redirect(Request $request)
{
$redirect = Socialite::driver('qq')->redirect();
return redirect($redirect);
}
/**
* 從 QQ 獲取用戶信息
*
*/
public function callback(Request $request)
{
$code = $request->input('code');
$qqUser = Socialite::driver('qq')->userFromCode($code);
//示例
$user = User::where('qq_id', $qqUser->id)->first();
if ($user) {
$user->update([
'qq_token' => $qqUser->access_token,
'qq_refresh_token' => $qqUser->refresh_token,
]);
} else {
$user = User::create([
'name' => $qqUser->name,
'email' => $qqUser->email,
'qq_id' => $qqUser->id,
'qq_token' => $qqUser->access_token,
'qq_refresh_token' => $qqUser->refresh_token,
]);
}
Auth::login($user);
return redirect('/index');
}
}
配置
擴(kuò)展自定義服務(wù)提供程序
你可以很輕松的對(duì)socialite進(jìn)行擴(kuò)展來(lái)滿足你不同的第三方登入需求
1.直接在config配置里添加你的應(yīng)用驅(qū)動(dòng)
'driver' => [
..
'line' => [
'provider' => \app\provider\LineProvider::class,
'client_id' => 'your-app-id',
'client_secret' => 'your-app-secret',
'redirect' => 'http://your-callback-url',
],
..
];
$socialite = Socialite::driver('line')->redirect();
2.使用閉包函數(shù)進(jìn)行擴(kuò)展
$config = [
'line' =>[
'provider' => 'line',
'client_id' => 'your-app-id',
'client_secret' => 'your-app-secret',
'redirect' => 'http://your-callback-url',
]
];
$socialite = Socialite::config(new \Shopwwi\WebmanSocialite\Config($config))->extend('line', function(array $config) {
return new LineProvider($config);
})->driver('line')->redirect();
// 下面直接注入也是可以的哈
$config = [
'line' =>[
'provider' => \app\provider\LineProvider::class,
'client_id' => 'your-app-id',
'client_secret' => 'your-app-secret',
'redirect' => 'http://your-callback-url',
]
];
$socialite = Socialite::config(new \Shopwwi\WebmanSocialite\Config($config))->driver('line')->redirect();
3.接下來(lái)為 AppleProvider
設(shè)置實(shí)際操作方法:
你的自定義服務(wù)提供類(lèi)必須實(shí)現(xiàn)\Shopwwi\WebmanSocialite\Contracts\Provider
接口
namespace app\provider;
class LineProvider implements \Shopwwi\WebmanSocialite\Contracts\Provider
{
//...
}
下面的示例繼承了 \Shopwwi\WebmanSocialite\Providers\AbstractProvider
大多數(shù)邏輯都是實(shí)現(xiàn)好了的 微調(diào)即可
namespace app\provider;
use Shopwwi\WebmanSocialite\Providers\AbstractProvider;
use Shopwwi\WebmanSocialite\Contracts;
use Shopwwi\WebmanSocialite\AbstractUser;
class LineProvider extends AbstractProvider
{
public const NAME = 'line';
protected string $baseUrl = 'https://api.line.me/oauth2/';
protected string $version = 'v2.1';
protected array $scopes = ['profile'];
protected function getAuthUrl(): string
{
$this->state = $this->state ?: \md5(\uniqid(Contracts\SHOPWWI_SOC_STATE, true));
return $this->buildAuthUrlFromBase('https://access.line.me/oauth2/'.$this->version.'/authorize');
}
protected function getTokenUrl(): string
{
return $this->baseUrl.$this->version.'/token';
}
/**
* @param string $code
* @return array
*/
protected function getTokenFields(string $code): array
{
return parent::getTokenFields($code) + [Contracts\SHOPWWI_SOC_GRANT_TYPE => Contracts\SHOPWWI_SOC_AUTHORIZATION_CODE];
}
/**
* @param string $token
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
*/
protected function getUserByToken(string $token): array
{
$response = $this->getHttpClient()->get(
'https://api.line.me/v2/profile',
[
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer '.$token,
],
]
);
return $this->fromJsonBody($response);
}
/**
* @param array $user
* @return Contracts\User
*/
protected function mapUserToObject(array $user): Contracts\User
{
return new AbstractUser([
Contracts\SHOPWWI_SOC_ID => $user['userId'] ?? null,
Contracts\SHOPWWI_SOC_NAME => $user['displayName'] ?? null,
Contracts\SHOPWWI_SOC_NICKNAME => $user['displayName'] ?? null,
Contracts\SHOPWWI_SOC_AVATAR => $user['pictureUrl'] ?? null,
Contracts\SHOPWWI_SOC_EMAIL => null,
]);
}
}
平臺(tái)
不同的平臺(tái)有不同的配置方法,為了確保工具的正常運(yùn)行,所以請(qǐng)確保你所使用的平臺(tái)的配置都是如期設(shè)置的。
支付寶
請(qǐng)按如下方式配置
$code = \request()->input('code');
$user = Socialite::driver('alipay')->userFromCode($code);
// 詳見(jiàn)文檔后面 "User interface"
$user->getId();
$user->getNickname();
$user->getUsername();
$user->getName();
...
釘釘
如文檔所示
注意:該工具僅支持 QR code 連接到第三方網(wǎng)站,用來(lái)獲取用戶信息(openid, unionid 和 nickname)
$code = \request()->input('code');
$user = Socialite::driver('dingtalk')->userFromCode($code);
// 詳見(jiàn)文檔后面 "User interface"
$user->getId();
$user->getNickname();
$user->getUsername();
$user->getName();
...
抖音
$code = \request()->input('code');
$user = Socialite::driver('douyin')->userFromCode($code);
// 通過(guò)access_token獲取用戶信息時(shí),需先設(shè)置openId
$openId = '4154d454..5561';
$token = '';
$user = Socialite::driver('douyin')->withOpenId($openId)->userFromToken($token);
頭條
$code = \request()->input('code');
$user = Socialite::driver('toutiao')->userFromCode($code);
// 通過(guò)access_token獲取用戶信息時(shí),需先設(shè)置openId
$openId = '4154d454..5561';
$token = '';
$user = Socialite::driver('toutiao')->withOpenId($openId)->userFromToken($token);
西瓜
$code = \request()->input('code');
$user = Socialite::driver('toutiao')->userFromCode($code);
//通過(guò)access_token獲取用戶信息時(shí),需先設(shè)置openId
$openId = '4154d454..5561';
$token = '';
$user = Socialite::driver('toutiao')->withOpenId($openId)->userFromToken($token);
百度
其他配置沒(méi)啥區(qū)別,在用法上,可以很輕易的選擇重定向登錄頁(yè)面的模式,通過(guò) withDisplay()
- page:全屏形式的授權(quán)頁(yè)面 (默認(rèn)),適用于 web 應(yīng)用。
- popup: 彈框形式的授權(quán)頁(yè)面,適用于桌面軟件應(yīng)用和 web 應(yīng)用。
- dialog: 浮層形式的授權(quán)頁(yè)面,只能用于站內(nèi) web 應(yīng)用。
- mobile: Iphone/Android 等智能移動(dòng)終端上用的授權(quán)頁(yè)面,適用于 Iphone/Android 等智能移動(dòng)終端上的應(yīng)用。
- tv: 電視等超大顯示屏使用的授權(quán)頁(yè)面。
- pad: IPad/Android 等智能平板電腦使用的授權(quán)頁(yè)面。
$authUrl = Socialite::driver('baidu')->withDisplay('mobile')->redirect();
popup
模式是工具內(nèi)默認(rèn)的使用模式。basic
是默認(rèn)使用的 scopes 值。
飛書(shū)
通過(guò)一些簡(jiǎn)單的方法配置 app_ticket 就能使用內(nèi)部應(yīng)用模式
$code = \request()->input('code');
$user = Socialite::driver('feishu')->withInternalAppMode()->userFromCode($code);
$appTicket = '';
$code = \request()->input('code');
$user = Socialite::driver('feishu')->withDefaultMode()->withAppTicket($appTicket)->userFromCode($code);
Lark
通過(guò)一些簡(jiǎn)單的方法配置 app_ticket 就能使用內(nèi)部應(yīng)用模式
$code = \request()->input('code');
$user = Socialite::driver('lark')->withInternalAppMode()->userFromCode($code);
$appTicket = '';
$code = \request()->input('code');
$user = Socialite::driver('lark')->withDefaultMode()->withAppTicket($appTicket)->userFromCode($code);
淘寶
其他配置與其他平臺(tái)的一樣,你能選擇你想要展示的重定向頁(yè)面類(lèi)型通過(guò)使用 withView()
$authUrl = Socialite::driver('taobao')->withView('wap')->redirect();
web
模式是工具默認(rèn)使用的展示方式, user_info
是默認(rèn)使用的 scopes 范圍值。
微信
我們支持開(kāi)放平臺(tái)代表公眾號(hào)進(jìn)行第三方平臺(tái)網(wǎng)頁(yè)授權(quán)。
你只需要像下面這樣輸入你的配置。官方賬號(hào)不需要授權(quán)。
'wechat' => [
'provider' => \Shopwwi\WebmanSocialite\Providers\WeChatProvider::class,
'client_id' => 'your-app-id',
'client_secret' => 'your-app-secret',
'redirect' => 'http://your-callback-url',
// 開(kāi)放平臺(tái) - 第三方平臺(tái)所需
'component' => [
// or 'app_id', 'component_app_id' as key
'id' => 'component-app-id',
// or 'app_token', 'access_token', 'component_access_token' as key
'token' => 'component-access-token',
]
],
Coding
您需要額外配置 team_url
為您的團(tuán)隊(duì)域名
其他一些技巧
訪問(wèn)作用域
在重定向用戶之前,你還可以使用 scopes
方法在請(qǐng)求中添加其他「作用域」。此方法將覆蓋所有現(xiàn)有的作用域:
$redirect = Socialite::driver('qq')->scopes(['scope1', 'scope2'])->redirect();
回調(diào)鏈接
你也可以動(dòng)態(tài)設(shè)置 redirect_uri
,你可以使用以下方法來(lái)改變 redirect_uri
URL:
$url = 'your callback url.';
Socialite::driver('qq')->redirect($url);
// or
Socialite::driver('qq')->withRedirectUrl($url)->redirect();
State
你的應(yīng)用程序可以使用一個(gè)狀態(tài)參數(shù)來(lái)確保響應(yīng)屬于同一個(gè)用戶發(fā)起的請(qǐng)求,從而防止跨站請(qǐng)求偽造 (CSFR) 攻擊。當(dāng)惡意攻擊者欺騙用戶執(zhí)行不需要的操作 (只有用戶有權(quán)在受信任的 web 應(yīng)用程序上執(zhí)行) 時(shí),就會(huì)發(fā)生 CSFR 攻擊,所有操作都將在不涉及或警告用戶的情況下完成。
這里有一個(gè)最簡(jiǎn)單的例子,說(shuō)明了如何提供狀態(tài)可以讓你的應(yīng)用程序更安全。在本例中,我們使用會(huì)話 ID 作為狀態(tài)參數(shù),但是您可以使用您想要為狀態(tài)創(chuàng)建值的任何邏輯。
帶著 state
參數(shù)的重定向
<?php
session_start();
// Assign to state the hashing of the session ID
$state = hash('sha256', session_id());
$url = Socialite::driver('qq')->withState($state)->redirect();
return redirect($url);
檢驗(yàn)回調(diào)的 state
一旦用戶授權(quán)你的應(yīng)用程序,用戶將被重定向回你的應(yīng)用程序的 redirect_uri。OAuth 服務(wù)器將不加修改地返回狀態(tài)參數(shù)。檢查 redirect_uri 中提供的狀態(tài)是否與應(yīng)用程序生成的狀態(tài)相匹配:
<?php
session_start();
$state = \request()->input('state');
$code = \request()->input('code');
// Check the state received with current session id
if ($state != hash('sha256', session_id())) {
exit('State does not match!');
}
$user = Socialite::driver('qq')->userFromCode($code);
// authorized
可選參數(shù)
許多 OAuth providers 支持重定向請(qǐng)求中的可選參數(shù)。 要在請(qǐng)求中包含任何可選參數(shù),請(qǐng)使用關(guān)聯(lián)數(shù)組調(diào)用 with
方法:
$response = Socialite::driver('qq')->with(['hd' => 'example.com'])->redirect();
返回用戶信息
標(biāo)準(zhǔn)的 user api:
$user = Socialite::driver('qq')->userFromCode($code);
你可以像這樣以數(shù)組鍵的形式獲取 user 屬性:
$user['id'];
$user['nickname'];
$user['name'];
$user['email'];
...
或者使用該 User
對(duì)象的方法:
$user->getId();
$user->getNickname();
$user->getName();
$user->getEmail();
$user->getAvatar();
$user->getRaw();
$user->getAccessToken();
$user->getRefreshToken();
$user->getExpiresIn();
$user->getTokenResponse();
從 OAuth API 響應(yīng)中取得原始數(shù)據(jù)
$user->getRaw()
方法會(huì)返回一個(gè) array。
當(dāng)你使用 userFromCode() 想要獲取 token 響應(yīng)的原始數(shù)據(jù)
$user->getTokenResponse()
方法會(huì)返回一個(gè) array 里面是響應(yīng)從獲取 token 時(shí)候 API 返回的響應(yīng)。
注意:當(dāng)你使用
userFromCode()
時(shí),這個(gè)方法只返回一個(gè) 有效的數(shù)組,否則將返回 null,因?yàn)?userFromToken()
沒(méi)有 token 的 HTTP 響應(yīng)。
通過(guò) access token 獲取用戶信息
$accessToken = 'xxxxxxxxxxx';
$user = $socialite->userFromToken($accessToken);
參照
- Alipay - 用戶信息授權(quán)
- DingTalk - 掃碼登錄第三方網(wǎng)站
- Google - OpenID Connect
- Github - Authorizing OAuth Apps
- Facebook - Graph API
- Linkedin - Authenticating with OAuth 2.0
- 微博 - OAuth 2.0 授權(quán)機(jī)制說(shuō)明
- QQ - OAuth 2.0 登錄 QQ
- 騰訊云 - OAuth2.0
- 微信公眾平臺(tái) - OAuth 文檔
- 微信開(kāi)放平臺(tái) - 網(wǎng)站應(yīng)用微信登錄開(kāi)發(fā)指南
- 微信開(kāi)放平臺(tái) - 代公眾號(hào)發(fā)起網(wǎng)頁(yè)授權(quán)
- 企業(yè)微信 - OAuth 文檔
- 企業(yè)微信第三方應(yīng)用 - OAuth 文檔
- 豆瓣 - OAuth 2.0 授權(quán)機(jī)制說(shuō)明
- 抖音 - 網(wǎng)站應(yīng)用開(kāi)發(fā)指南
- 飛書(shū) - 授權(quán)說(shuō)明
- Lark - 授權(quán)說(shuō)明
- Tapd - 用戶授權(quán)說(shuō)明
- Line - OAuth 2.0
- Gitee - OAuth文檔
License
MIT