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

Laravel Passport与Socialite实现SSO登录后无法跳转回调问题

问题描述

我正在开发一个基于Laravel Passport的应用B,用于为同体系的其他Laravel应用处理授权,当前设定的流程如下:

  • 应用A的用户点击登录按钮
  • 跳转至应用B
  • 若用户已登录,直接跳转至回调地址
  • 若用户未登录,引导其通过Google账号登录后跳转回调地址

目前遇到的问题:用户完成登录后无法跳转至应用A的回调地址,流程卡在回调环节。


相关代码与配置

SocialiteController.php

class SocialiteController extends Controller
{
    public function redirectProvider()
    {
        return Socialite::driver('github')->stateless()->redirect();
    }

    public function callbackProvider()
    {
        // 获取尝试登录的用户
        $githubUser = Socialite::driver('github')->stateless()->user();

        // 检查用户是否存在,不存在则创建
        $user = User::updateOrCreate([
            'email' => $githubUser->email
        ], [
            'name' => $githubUser->name,
            'email' => $githubUser->email,
            'github_token' => $githubUser->token,
            'github_refresh_token' => $githubUser->refresh_token,
            'last_login' => now()
        ]);

        // 为用户创建认证令牌

        Auth::guard('api')->setUser($user);

        // 此处应跳转至应用A,并带上获取Bearer令牌所需的code查询参数

    }
}

config/auth.php

'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],

'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'api' => [
            'driver' => 'passport',
            'provider' => 'users',
        ]
    ],

config/passport.php 中的guard配置

'guard' => 'web',

路由配置

Route::controller(SocialiteController::class)->group(function () {
    Route::get('redirect', 'redirectProvider')->name('socialite.redirect');
    Route::get('callback', 'callbackProvider')->name('socialite.callback');
});

授权请求示例URL

http://localhost:7003/oauth/authorize?client_id=9a622876-4a3a-4046-a41d-76b303fa0f4e&redirect_uri=http://localhost:7005&response_type=code&scope=*


解决方案

问题核心是丢失了应用A发起授权请求时的上下文参数,导致Google登录回调后无法恢复Passport的授权流程。按以下步骤修正:

  1. 保存授权请求参数
    修改redirectProvider方法,把应用A传来的授权参数暂存到session:
public function redirectProvider()
{
    // 保存授权请求的关键参数
    session()->put('oauth_request', request()->only('client_id', 'redirect_uri', 'response_type', 'scope', 'state'));
    
    return Socialite::driver('github')->stateless()->redirect();
}
  1. 回调后恢复授权流程
    用户登录成功后,取出暂存的参数,生成Passport授权码并跳转回应用A:
public function callbackProvider()
{
    $githubUser = Socialite::driver('github')->stateless()->user();

    $user = User::updateOrCreate([
        'email' => $githubUser->email
    ], [
        'name' => $githubUser->name,
        'email' => $githubUser->email,
        'github_token' => $githubUser->token,
        'github_refresh_token' => $githubUser->refresh_token,
        'last_login' => now()
    ]);

    // 使用web guard登录用户(Passport授权流程依赖session认证)
    Auth::guard('web')->login($user);

    // 取出之前保存的授权参数
    $oauthRequest = session()->pull('oauth_request');
    
    // 查找对应客户端
    $client = \Laravel\Passport\Client::find($oauthRequest['client_id']);
    
    // 创建授权码
    $authCode = \Laravel\Passport\AuthCode::create([
        'user_id' => $user->id,
        'client_id' => $client->id,
        'scopes' => explode(' ', $oauthRequest['scope']),
        'redirect_uri' => $oauthRequest['redirect_uri'],
        'expires_at' => now()->addMinutes(5),
    ]);

    // 拼接跳转URL,携带授权码和state参数
    $redirectUrl = $oauthRequest['redirect_uri'] . '?code=' . $authCode->id . '&state=' . $oauthRequest['state'];
    
    return redirect($redirectUrl);
}
  1. 确认session配置正常
    确保应用B的session配置(config/session.php)有效,因为我们需要用session暂存授权参数。

内容的提问来源于stack exchange,提问作者sNok3

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 09:57:27