Laravel中Socialite登录后调用API返回401未授权问题
问题根源
这个401错误的核心问题很明确:Web端通过Socialite登录用的是Session认证,但你的API路由用了auth:sanctum中间件,默认要求请求携带Sanctum Token。现在前端调用API时既没带Token,也没配置让Sanctum识别已有的Session登录状态,所以接口不认当前登录用户。
两种解决方案
根据你的项目场景(同域/跨域)选一种就行:
方案1:让Sanctum识别Session登录(同域前端用这个)
如果你的Vue前端和后端是同域的,最简单的办法是让Sanctum支持Session认证:
- 修改
config/sanctum.php里的stateful数组,把你的前端域名加进去,比如前端跑在localhost:8080,就改成:
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( '%s%s', 'localhost,localhost:3000,localhost:8080,127.0.0.1,127.0.0.1:8000,::1', env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : '' ))),
- 给Axios开启自动携带Cookie的配置,在Vue项目里全局设置:
axios.defaults.withCredentials = true;
这样同域的API请求会自动携带Session Cookie,Sanctum就能认出登录的用户了,不用额外传Token。
方案2:生成Token传给前端(跨域/前后端分离用这个)
如果是跨域场景,就得生成Sanctum Token并让前端存下来,请求时带上:
- 先修复Socialite回调里的Token逻辑,不管新老用户都生成Token并存好,还要传给前端:
public function handleProviderCallback($provider) { try { $user_social = Socialite::driver($provider)->stateless()->user(); $current_user = UserSocial::where("account_id", $user_social->getId())->first(); $user = null; $token = ''; if ($current_user) { $user = User::findOrFail($current_user->user_id); // 给老用户生成新Token $token = $user->createToken('social-login')->plainTextToken; $current_user->token = $token; $current_user->save(); } else { $user = new User(); $user->name = $user_social->getName(); $user->email = $user_social->getEmail(); $user->password = bcrypt($user_social->getId()); $user->login_with = $provider; $user->assignRole(User::ROLE_USER); $user->save(); $token = $user->createToken('social-login')->plainTextToken; $user_account = new UserSocial(); $user_account->user_id = $user->id; $user_account->account_id = $user_social->getId(); $user_account->provider = $provider; $user_account->token = $token; $user_account->save(); } Auth::login($user); // 把Token存到Session,前端页面渲染时能拿到 session(['sanctum_token' => $token]); return redirect()->intended("/"); } catch (ClientException $exception) { return $this->errorResponse(["message" => "Invalid credentials provided."]); } }
- 前端拿到Token后,给Axios加请求头:
比如后端在页面里把Token注入成全局变量,然后:
const token = window.sanctumToken; axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
或者从页面的meta标签取:
const token = document.querySelector('meta[name="sanctum-token"]').content; axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
必做检查
- 你的
User模型必须引入HasApiTokenstrait,不然生成不了Token:
use Laravel\Sanctum\HasApiTokens; class User extends Authenticatable { use HasApiTokens, HasFactory, Notifiable; // ... }
- 如果用方案1,还要修改
config/cors.php里的supports_credentials为true,不然Cookie传不过去。
内容的提问来源于stack exchange,提问作者Ahmad Schofield
相关产品推荐
相关产品推荐

