接入微信、GitHub、Google 等第三方登录。
OAuth2.0 流程 用户 → 点击第三方登录 → 跳转授权页 → 用户授权 → 回调带 code ↓ code 换 access_token → 获取用户信息
GitHub 登录
<?php
class GitHubOAuth
{
private string $clientId;
private string $clientSecret;
private string $redirectUri;
// 生成授权链接
public function getAuthUrl(string $state = ''): string
{
$params = http_build_query([
'client_id' => $this->clientId,
'redirect_uri' => $this->redirectUri,
'scope' => 'user:email',
'state' => $state ?: Str::random(16)
]);
return "https://github.com/login/oauth/authorize?{$params}";
}
// code 换 token
public function getAccessToken(string $code): string
{
$response = Http::post('https://github.com/login/oauth/access_token', [
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret,
'code' => $code
])->body();
parse_str($response, $data);
if (!isset($data['access_token'])) {
throw new Exception('获取 access_token 失败');
}
return $data['access_token'];
}
// 获取用户信息
public function getUserInfo(string $accessToken): array
{
$response = Http::withHeaders([
'Authorization' => "Bearer {$accessToken}"
])->get('https://api.github.com/user')->json();
return [
'id' => $response['id'],
'username' => $response['login'],
'nickname' => $response['name'],
'avatar' => $response['avatar_url'],
'email' => $response['email']
];
}
}
微信登录(开放平台)
<?php
class WechatOAuth
{
// 生成授权链接(PC 扫码)
public function getAuthUrl(string $state = ''): string
{
$params = http_build_query([
'appid' => $this->appId,
'redirect_uri' => urlencode($this->redirectUri),
'response_type' => 'code',
'scope' => 'snsapi_login',
'state' => $state
]);
return "https://open.weixin.qq.com/connect/qrconnect?{$params}[#wechat]()_redirect";
}
// code 换 token
public function getAccessToken(string $code): array
{
$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->appId}&secret={$this->appSecret}&code={$code}&grant_type=authorization_code";
return Http::get($url)->json();
}
// 获取用户信息
public function getUserInfo(string $accessToken, string $openid): array
{
$url = "https://api.weixin.qq.com/sns/userinfo?access_token={$accessToken}&openid={$openid}";
$response = Http::get($url)->json();
return [
'openid' => $response['openid'],
'unionid' => $response['unionid'] ?? null,
'nickname' => $response['nickname'],
'avatar' => $response['headimgurl']
];
}
}
统一封装
<?php
interface OAuthProvider
{
public function getAuthUrl(string $state = ''): string;
public function getAccessToken(string $code): string;
public function getUserInfo(string $accessToken): array;
}
class OAuthService
{
private array $providers = [];
public function __construct()
{
$this->providers = [
'github' => new GitHubOAuth(config('oauth.github')),
'wechat' => new WechatOAuth(config('oauth.wechat')),
'google' => new GoogleOAuth(config('oauth.google'))
];
}
public function redirect(string $provider): RedirectResponse
{
$state = Str::random(16);
session(['oauth_state' => $state]);
return redirect($this->providers[$provider]->getAuthUrl($state));
}
public function callback(string $provider, string $code, string $state): User
{
// 验证 state
if ($state !== session('oauth_state')) {
throw new Exception('Invalid state');
}
$oauth = $this->providers[$provider];
$accessToken = $oauth->getAccessToken($code);
$oauthUser = $oauth->getUserInfo($accessToken);
// 查找或创建用户
$socialAccount = SocialAccount::firstOrCreate([
'provider' => $provider,
'provider_id' => $oauthUser['id']
], [
'nickname' => $oauthUser['nickname'],
'avatar' => $oauthUser['avatar']
]);
if (!$socialAccount->user_id) {
// 创建新用户
$user = User::create([
'nickname' => $oauthUser['nickname'],
'avatar' => $oauthUser['avatar']
]);
$socialAccount->update(['user_id' => $user->id]);
}
return $socialAccount->user;
}
}
数据库设计
CREATE TABLE social_accounts (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NULL,
provider VARCHAR(20),
provider_id VARCHAR(100),
nickname VARCHAR(100),
avatar VARCHAR(255),
access_token VARCHAR(255),
refresh_token VARCHAR(255),
expires_at TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uk_provider (provider, provider_id),
INDEX idx_user (user_id)
);
控制器
<?php
class OAuthController
{
public function redirect(string $provider)
{
return $this->oauthService->redirect($provider);
}
public function callback(Request $request, string $provider)
{
$user = $this->oauthService->callback(
$provider,
$request->input('code'),
$request->input('state')
);
Auth::login($user);
return redirect('/');
}
}
// routes/web.php
Route::get('/oauth/{provider}', [OAuthController::class, 'redirect']);
Route::get('/oauth/{provider}/callback', [OAuthController::class, 'callback']);
总结
| 平台 | 授权域名 |
|---|---|
| GitHub | github.com/login/oauth |
| 微信 | open.weixin.qq.com |
| accounts.google.com | |
| graph.qq.com |
OAuth2.0 是标准协议,各平台流程基本一致,只是参数略有不同。