本文目录导读:

- 安装依赖包
- 配置文件 config/services.php
- .env 配置
- 创建数据表迁移
- 创建模型
- 创建服务类
- 创建控制器
- 路由配置
- Blade 视图示例
- 扩展:自定义QQ驱动
- 配置文件补充(如需自定义驱动)
- 安全建议
我来帮你实现Laravel项目的第三方登录多驱动功能,以下是完整的实现方案:
安装依赖包
composer require laravel/socialite
配置文件 config/services.php
<?php
return [
// ... 其他配置
'github' => [
'client_id' => env('GITHUB_CLIENT_ID'),
'client_secret' => env('GITHUB_CLIENT_SECRET'),
'redirect' => env('GITHUB_REDIRECT_URI'),
],
'wechat' => [
'client_id' => env('WECHAT_CLIENT_ID'),
'client_secret' => env('WECHAT_CLIENT_SECRET'),
'redirect' => env('WECHAT_REDIRECT_URI'),
],
'qq' => [
'client_id' => env('QQ_CLIENT_ID'),
'client_secret' => env('QQ_CLIENT_SECRET'),
'redirect' => env('QQ_REDIRECT_URI'),
],
'weibo' => [
'client_id' => env('WEIBO_CLIENT_ID'),
'client_secret' => env('WEIBO_CLIENT_SECRET'),
'redirect' => env('WEIBO_REDIRECT_URI'),
],
];
.env 配置
# GitHub GITHUB_CLIENT_ID=your_github_client_id GITHUB_CLIENT_SECRET=your_github_client_secret GITHUB_REDIRECT_URI=http://localhost:8000/auth/github/callback # 微信 WECHAT_CLIENT_ID=your_wechat_appid WECHAT_CLIENT_SECRET=your_wechat_secret WECHAT_REDIRECT_URI=http://localhost:8000/auth/wechat/callback # QQ QQ_CLIENT_ID=your_qq_appid QQ_CLIENT_SECRET=your_qq_appkey QQ_REDIRECT_URI=http://localhost:8000/auth/qq/callback # 微博 WEIBO_CLIENT_ID=your_weibo_appkey WEIBO_CLIENT_SECRET=your_weibo_secret WEIBO_REDIRECT_URI=http://localhost:8000/auth/weibo/callback
创建数据表迁移
// database/migrations/xxxx_create_oauth_logins_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateOauthLoginsTable extends Migration
{
public function up()
{
Schema::create('oauth_logins', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id')->nullable();
$table->string('provider'); // github, wechat, qq, weibo
$table->string('provider_user_id'); // 第三方用户ID
$table->string('nickname')->nullable();
$table->string('avatar')->nullable();
$table->string('email')->nullable();
$table->json('meta')->nullable(); // 额外的用户信息
$table->timestamps();
$table->unique(['provider', 'provider_user_id']);
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
public function down()
{
Schema::dropIfExists('oauth_logins');
}
}
创建模型
<?php
// app/Models/OauthLogin.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class OauthLogin extends Model
{
protected $fillable = [
'user_id', 'provider', 'provider_user_id',
'nickname', 'avatar', 'email', 'meta'
];
protected $casts = [
'meta' => 'array'
];
public function user()
{
return $this->belongsTo(User::class);
}
}
创建服务类
<?php
// app/Services/OAuthService.php
namespace App\Services;
use App\Models\User;
use App\Models\OauthLogin;
use Laravel\Socialite\Contracts\User as SocialUser;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
class OAuthService
{
/**
* 支持的第三方登录驱动
*/
protected $providers = [
'github' => 'github',
'wechat' => 'wechat',
'qq' => 'qq',
'weibo' => 'weibo',
];
/**
* 检查驱动是否支持
*/
public function providerExists($provider): bool
{
return array_key_exists($provider, $this->providers);
}
/**
* 获取支持的驱动列表
*/
public function getProviders(): array
{
return array_keys($this->providers);
}
/**
* 处理第三方登录
*/
public function handleOAuthCallback($provider, SocialUser $socialUser)
{
// 查找是否已绑定
$oauthLogin = OauthLogin::where('provider', $provider)
->where('provider_user_id', $socialUser->getId())
->first();
if ($oauthLogin && $oauthLogin->user) {
// 已绑定,直接登录
Auth::login($oauthLogin->user);
$oauthLogin->update([
'nickname' => $socialUser->getNickname() ?? $socialUser->getName(),
'avatar' => $socialUser->getAvatar(),
'email' => $socialUser->getEmail(),
'meta' => $this->getUserData($socialUser),
]);
return $oauthLogin->user;
}
// 未绑定,创建新用户或提示绑定
return $this->handleNewUser($provider, $socialUser);
}
/**
* 处理新用户
*/
protected function handleNewUser($provider, SocialUser $socialUser)
{
// 检查邮箱是否已存在
$email = $socialUser->getEmail();
if ($email) {
$user = User::where('email', $email)->first();
if ($user) {
// 邮箱已存在,自动绑定
$this->bindOAuthToUser($user, $provider, $socialUser);
Auth::login($user);
return $user;
}
}
// 创建新用户
$user = User::create([
'name' => $socialUser->getNickname() ?? $socialUser->getName() ?? '用户' . Str::random(6),
'email' => $email ?? $this->generateVirtualEmail($provider, $socialUser->getId()),
'password' => bcrypt(Str::random(32)),
'avatar' => $socialUser->getAvatar(),
'email_verified_at' => $email ? now() : null,
]);
$this->bindOAuthToUser($user, $provider, $socialUser);
Auth::login($user);
return $user;
}
/**
* 绑定第三方登录到用户
*/
public function bindOAuthToUser($user, $provider, SocialUser $socialUser)
{
return OauthLogin::updateOrCreate(
[
'provider' => $provider,
'provider_user_id' => $socialUser->getId(),
],
[
'user_id' => $user->id,
'nickname' => $socialUser->getNickname() ?? $socialUser->getName(),
'avatar' => $socialUser->getAvatar(),
'email' => $socialUser->getEmail(),
'meta' => $this->getUserData($socialUser),
]
);
}
/**
* 获取完整用户数据
*/
protected function getUserData(SocialUser $socialUser): array
{
$raw = $socialUser->getRaw();
return [
'raw' => $raw,
'token' => $socialUser->token,
'refresh_token' => $socialUser->refreshToken ?? null,
'expires_in' => $socialUser->expiresIn ?? null,
];
}
/**
* 生成虚拟邮箱
*/
protected function generateVirtualEmail($provider, $providerUserId): string
{
return "{$provider}-{$providerUserId}@oauth.local";
}
/**
* 解绑第三方登录
*/
public function unbindOAuth($user, $provider)
{
return OauthLogin::where('user_id', $user->id)
->where('provider', $provider)
->delete();
}
/**
* 获取用户绑定的第三方账号
*/
public function getUserOAuthLogins($user)
{
return OauthLogin::where('user_id', $user->id)->get();
}
}
创建控制器
<?php
// app/Http/Controllers/Auth/OAuthController.php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Services\OAuthService;
use Laravel\Socialite\Facades\Socialite;
use Illuminate\Http\Request;
class OAuthController extends Controller
{
protected $oauthService;
public function __construct(OAuthService $oauthService)
{
$this->oauthService = $oauthService;
}
/**
* 跳转到第三方登录页面
*/
public function redirect($provider)
{
if (!$this->oauthService->providerExists($provider)) {
abort(404, '不支持的第三方登录方式');
}
return Socialite::driver($provider)->redirect();
}
/**
* 处理第三方登录回调
*/
public function callback($provider)
{
if (!$this->oauthService->providerExists($provider)) {
abort(404, '不支持的第三方登录方式');
}
try {
$socialUser = Socialite::driver($provider)->user();
$user = $this->oauthService->handleOAuthCallback($provider, $socialUser);
// 登录成功后的处理
return redirect()->route('home')->with('success', '登录成功');
} catch (\Exception $e) {
\Log::error('OAuth登录失败', [
'provider' => $provider,
'error' => $e->getMessage()
]);
return redirect()->route('login')
->with('error', '第三方登录失败,请重试');
}
}
}
路由配置
<?php
// routes/web.php
use App\Http\Controllers\Auth\OAuthController;
// 第三方登录
Route::prefix('auth')->group(function () {
Route::get('{provider}', [OAuthController::class, 'redirect'])->name('oauth.redirect');
Route::get('{provider}/callback', [OAuthController::class, 'callback'])->name('oauth.callback');
});
Blade 视图示例
{{-- resources/views/auth/login.blade.php --}}
<div class="oauth-login">
<div class="oauth-title">其他登录方式</div>
@if($oauthLogins)
{{-- 显示已绑定的账号 --}}
<div class="bound-accounts">
@foreach($oauthLogins as $oauth)
<div class="account-item">
<span>{{ $oauth->provider }}: {{ $oauth->nickname }}</span>
<form action="{{ route('oauth.unbind', $oauth->provider) }}" method="POST">
@csrf
<button type="submit">解绑</button>
</form>
</div>
@endforeach
</div>
@endif
<div class="oauth-buttons">
<a href="{{ route('oauth.redirect', 'github') }}" class="btn btn-github">
<i class="fab fa-github"></i> GitHub 登录
</a>
<a href="{{ route('oauth.redirect', 'wechat') }}" class="btn btn-wechat">
<i class="fab fa-weixin"></i> 微信登录
</a>
<a href="{{ route('oauth.redirect', 'qq') }}" class="btn btn-qq">
<i class="fab fa-qq"></i> QQ 登录
</a>
<a href="{{ route('oauth.redirect', 'weibo') }}" class="btn btn-weibo">
<i class="fab fa-weibo"></i> 微博登录
</a>
</div>
</div>
扩展:自定义QQ驱动
<?php
// app/Providers/AppServiceProvider.php
use SocialiteProviders\Manager\SocialiteWasCalled;
use SocialiteProviders\QQ\QQExtendSocialite;
public function boot()
{
// 注册QQ驱动
$this->app->make(\SocialiteProviders\Manager\SocialiteWasCalled::class)
->extend('qq', QQExtendSocialite::class);
}
配置文件补充(如需自定义驱动)
<?php
// config/services.php 补充
'qq' => [
'client_id' => env('QQ_CLIENT_ID'),
'client_secret' => env('QQ_CLIENT_SECRET'),
'redirect' => env('QQ_REDIRECT_URI'),
],
安全建议
-
验证回调状态
$socialUser = Socialite::driver($provider)->stateless()->user();
-
使用 state 参数
return Socialite::driver($provider) ->with(['state' => csrf_token()]) ->redirect();
-
日志记录
\Log::info('第三方登录', [ 'provider' => $provider, 'user_id' => $user->id, 'ip' => request()->ip(), 'time' => now() ]);
这样你就完成了Laravel多驱动第三方登录的完整实现,记得根据实际需求调整代码,并确保在 .env 中正确配置所有第三方平台的App ID和密钥。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播