You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 23:47:40