Laravel Socialite无状态模式Facebook授权码重复使用报错求助
问题描述
在Laravel后端(REST API)+Angular前端架构中实现Laravel Socialite无状态认证,可正常获取重定向URL,但输入Facebook凭据授权后,回调时出现以下错误:
Client error: `POST https://graph.facebook.com/v3.3/oauth/access_token` resulted in a `400 Bad Request` response: {"error":{"message":"This authorization code has been used.","type":"OAuthException","code":100,"error_subcode":36009,"f (truncated...)
相关代码
1. api.php路由
Route::get('/auth/redirect/{provider}', [AuthController::class, 'redirectToProvider']) ->where('provider', '[A-Za-z]+'); Route::get('/auth/{provider}/callback', [AuthController::class, 'handleProviderCallback']) ->where('provider', '[A-Za-z]+');
2. AuthController.php控制器方法
/** * @param $provider * @return JsonResponse */ public function redirectToProvider($provider): JsonResponse { $response = $this->authService->redirectToProvider($provider); return response()->json($response); } /** * @param $provider * @param Request $request * @return JsonResponse * @throws \App\Exceptions\Custom\CustomValidationException */ public function handleProviderCallback($provider, Request $request): JsonResponse { ValidationUtils::validate($request->all(), [ 'code' => 'required', ]); $response = $this->authService->handleProviderCallback($provider); return response()->json($response); }
3. AuthServiceImpl.php实现类方法
/** * @param $provider * @return array[] */ public function redirectToProvider($provider): array { if (!in_array($provider, self::PROVIDERS)) { throw new CustomNotFoundException(trans('errors.not_found.provider')); } $success['provider_redirect'] = Socialite::driver($provider)->stateless()->redirect()->getTargetUrl(); return [ 'data' => $success ]; } /** * @param $provider * @return array[]|void */ public function handleProviderCallback($provider) { if (!in_array($provider, self::PROVIDERS)) { throw new CustomNotFoundException(trans('errors.not_found.provider')); } try { $providerUser = Socialite::driver($provider)->stateless()->user(); if ($providerUser) { $user = $this->socialAccountsService->findOrCreate($providerUser, $provider); $user->markEmailAsVerified(); $token = $user->createToken(env('API_AUTH_TOKEN_PASSPORT_SOCIAL'))->accessToken; return [ 'data' => [ 'tokens' => [ 'token_type' => 'Bearer', 'expires_in' => 5400, 'access_token' => $token ], 'user' => new UserResource($user) ], 'message' => trans('auth.login') ]; } } catch (\Exception $e) { throw new CustomUnauthorizedException($e->getMessage()); } }
问题分析与修复方案
核心原因
错误提示授权码已被使用,结合代码来看,服务层的回调方法没有正确接收并使用前端传来的授权码code。在无状态模式下,Socialite无法自动获取请求中的code,必须手动传递。原代码中直接调用user()方法,会导致内部尝试使用无效/重复的code。
修复步骤
- 修改控制器,传递code到服务层
在AuthController.php的handleProviderCallback方法中,将请求中的code参数传给服务层:
$response = $this->authService->handleProviderCallback($provider, $request->code);
- 修改服务层方法,使用
userFromCode获取用户
在AuthServiceImpl.php的handleProviderCallback方法中,接收code参数,并调用userFromCode方法替代user():
/** * @param $provider * @param string $code * @return array[]|void */ public function handleProviderCallback($provider, string $code) { if (!in_array($provider, self::PROVIDERS)) { throw new CustomNotFoundException(trans('errors.not_found.provider')); } try { // 用userFromCode替代user(),手动传入授权码 $providerUser = Socialite::driver($provider)->stateless()->userFromCode($code); if ($providerUser) { $user = $this->socialAccountsService->findOrCreate($providerUser, $provider); $user->markEmailAsVerified(); $token = $user->createToken(env('API_AUTH_TOKEN_PASSPORT_SOCIAL'))->accessToken; return [ 'data' => [ 'tokens' => [ 'token_type' => 'Bearer', 'expires_in' => 5400, 'access_token' => $token ], 'user' => new UserResource($user) ], 'message' => trans('auth.login') ]; } } catch (\Exception $e) { throw new CustomUnauthorizedException($e->getMessage()); } }
- 额外检查项
- 前端回调逻辑:确保Facebook授权完成后,仅调用一次后端回调接口,避免重复提交同一个
code - Facebook应用配置:确认回调URL与后端设置完全一致,同时升级Graph API版本(当前v3.3过旧,建议使用v18.0等较新版本)
内容的提问来源于stack exchange,提问作者user13289818
相关产品推荐
相关产品推荐

