Laravel10中通过Passport实现客户端认证并改用Auth类替代Session
解决方案:用Laravel Auth替代Session实现Passport SSO客户端认证
1. 配置客户端认证系统
先调整config/auth.php的认证配置,使用会话驱动并自定义用户提供者,适配无本地用户表的场景:
// config/auth.php return [ 'defaults' => [ 'guard' => 'web', 'passwords' => 'users', ], 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'remote-users', // 自定义远程用户提供者 ], ], 'providers' => [ 'remote-users' => [ 'driver' => 'eloquent', 'model' => App\Models\RemoteUser::class, // 虚拟用户模型 ], ], ];
2. 创建虚拟用户模型
客户端无需本地用户表,创建一个实现Authenticatable接口的虚拟模型,用于Laravel Auth识别用户身份:
// app/Models/RemoteUser.php namespace App\Models; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Database\Eloquent\Model; class RemoteUser extends Model implements Authenticatable { use \Illuminate\Auth\Authenticatable; // 允许批量赋值服务端返回的用户字段 protected $fillable = ['id', 'name', 'email', 'avatar']; // 重写save方法避免无数据库表报错 public function save(array $options = []) { return true; } }
3. 重构回调函数逻辑
移除Session存储逻辑,改用Laravel Auth完成用户认证,同时保留令牌存储用于后续刷新:
public function callback(Request $request) { // 用授权码交换令牌 $tokenResponse = Http::asForm()->post('http://127.0.0.1:8000/oauth/token', [ 'grant_type' => 'authorization_code', 'client_id' => '993fed57-cb86-4c26-a001-a485ccea5334', 'client_secret' => 'UZUvZtPcrkOg4ICgeq5h87fH1hOFMYt7AujJPNBH', 'redirect_uri' => 'http://127.0.0.1:8001/login/oauth/callback', 'code' => $request->code, ])->json(); // 校验令牌请求结果 if (!isset($tokenResponse['access_token'])) { return redirect()->route('login')->withErrors('登录失败,请重试'); } // 从服务端获取用户信息 $userResponse = Http::withHeaders([ 'Accept' => 'application/json', 'Authorization' => 'Bearer ' . $tokenResponse['access_token'], ])->get('http://127.0.0.1:8000/api/user')->json(); // 创建虚拟用户实例并完成认证 $remoteUser = new \App\Models\RemoteUser($userResponse); \Illuminate\Support\Facades\Auth::login($remoteUser); // 存储令牌到数据库(用于自动刷新) \App\Models\OauthToken::updateOrCreate( ['user_id' => $userResponse['id']], [ 'token_type' => $tokenResponse['token_type'], 'access_token' => $tokenResponse['access_token'], 'refresh_token' => $tokenResponse['refresh_token'], 'expires_in' => now()->addSeconds($tokenResponse['expires_in']), ] ); return redirect()->intended('/dashboard'); }
4. 自动刷新令牌(可选)
创建中间件处理令牌过期自动刷新,避免用户频繁重新登录:
// app/Http/Middleware/RefreshAccessToken.php namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\Http; class RefreshAccessToken { public function handle($request, Closure $next) { if (Auth::check()) { $oauthToken = \App\Models\OauthToken::where('user_id', Auth::id())->first(); // 检查令牌是否已过期 if ($oauthToken && $oauthToken->expires_in->isPast()) { $refreshResponse = Http::asForm()->post('http://127.0.0.1:8000/oauth/token', [ 'grant_type' => 'refresh_token', 'client_id' => '993fed57-cb86-4c26-a001-a485ccea5334', 'client_secret' => 'UZUvZtPcrkOg4ICgeq5h87fH1hOFMYt7AujJPNBH', 'refresh_token' => $oauthToken->refresh_token, ])->json(); if (isset($refreshResponse['access_token'])) { // 更新数据库中的令牌信息 $oauthToken->update([ 'access_token' => $refreshResponse['access_token'], 'refresh_token' => $refreshResponse['refresh_token'], 'expires_in' => now()->addSeconds($refreshResponse['expires_in']), ]); } else { // 刷新失败,强制退出登录 Auth::logout(); return redirect()->route('login'); } } } return $next($request); } }
将该中间件注册到app/Http/Kernel.php的web中间件组或指定路由中。
5. 退出登录逻辑
退出时清理Auth会话和数据库中的令牌:
public function logout(Request $request) { if (Auth::check()) { \App\Models\OauthToken::where('user_id', Auth::id())->delete(); Auth::logout(); } $request->session()->invalidate(); $request->session()->regenerateToken(); return redirect('/'); }
核心优势
- 借助Laravel Auth内置的安全机制(会话加密、CSRF防护、会话过期)替代手动Session存储,提升安全性
- 虚拟用户模型仅作为Auth系统的身份载体,实际用户数据始终由服务端维护,避免数据不一致
- 令牌持久化存储支持自动刷新,优化用户登录体验
内容的提问来源于stack exchange,提问作者John Patrick Lachica
相关产品推荐
相关产品推荐

