Angular对接Laravel Sanctum后端:XSRF-TOKEN获取为空问题
Ionic Angular对接Laravel Sanctum获取XSRF令牌问题解决
问题核心
用Postman请求https://my_domain.com/sanctum-cookie能拿到204状态码和XSRF-TOKEN响应头,但Angular代码里同样返回204,却读不到任何响应头,导致拿不到令牌无法完成登录。
解决步骤
1. 后端CORS配置调整
Laravel必须显式允许前端读取Set-Cookie头,否则浏览器会默认隐藏这个敏感头。修改config/cors.php:
// 允许暴露Set-Cookie给前端读取 'exposed_headers' => ['Set-Cookie'], // 开启凭证支持,允许浏览器携带和接收cookie 'supports_credentials' => true,
同时检查config/sanctum.php的stateful配置,把你的前端域名加入列表,确保Sanctum认可该来源:
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', '你的前端域名,localhost:8100')),
2. Angular代码修复
关键错误修正
- 前端不需要设置
Access-Control-Allow-Origin这类响应头,这是后端的配置项,前端添加反而会干扰请求。 - 必须开启
withCredentials: true,否则浏览器不会接收或发送cookie。 - 原代码里
XSFR-TOKEN拼写错误,Sanctum要求的请求头是X-XSRF-TOKEN。 - 初始化的
headers是静态实例,拿到令牌后要动态更新请求头才能生效。
修改后的完整代码:
import { Injectable } from '@angular/core'; import { environment } from "src/environments/environment.prod"; import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'; import { UserService } from 'src/app/services/user/user.service'; @Injectable({ providedIn: 'root' }) export class AuthenticationService { xsrfToken: string = ''; constructor( private http: HttpClient, private user: UserService ) { } // 动态生成请求头,保证令牌更新后能同步到后续请求 private getRequestHeaders(): HttpHeaders { let headers = new HttpHeaders({ 'Content-Type': 'application/json', 'Accept': 'application/json' }); if (this.xsrfToken) { headers = headers.set('X-XSRF-TOKEN', this.xsrfToken); } return headers; } loginUser(credentials: { email: string; password: string }): Promise<{ success: boolean, user?: any }> { console.log('Logging in the user with credentials =>', credentials.email + ' ' + credentials.password); if (!credentials.email || !credentials.password) { return Promise.resolve({ success: false }); } // 获取Sanctum cookie和XSRF令牌 return this.http.get(`${environment.apiUrlForCookie}`, { headers: this.getRequestHeaders(), observe: 'response', withCredentials: true // 必须开启,否则拿不到cookie }).toPromise() .then((response: HttpResponse<any>) => { const setCookieHeader = response.headers.get('Set-Cookie'); if (setCookieHeader) { // 提取XSRF-TOKEN,注意解码(cookie值可能被URL编码) const xsrfMatch = setCookieHeader.match(/XSRF-TOKEN=([^;]+)/); if (xsrfMatch) { this.xsrfToken = decodeURIComponent(xsrfMatch[1]); console.log('CSRF Token:', this.xsrfToken); } } console.log('Set-Cookie Header =>', setCookieHeader); // 发起登录请求,同样开启withCredentials return this.http.post(`${environment.api}/login`, credentials, { headers: this.getRequestHeaders(), observe: 'response', withCredentials: true }).toPromise() .then((loginResponse: HttpResponse<any>) => { if (loginResponse.body?.status === 'error') { console.error('Error occurred:', loginResponse.body.message); return { success: false }; } else { console.log('User logged in:', loginResponse.body.user); return { success: true, user: loginResponse.body.user }; } }); }) .catch((error: any) => { console.error('Fatal error occurred:', error.message); return { success: false }; }); } }
3. 移动端额外配置(Ionic Capacitor)
如果是用Capacitor打包的App,需要在capacitor.config.ts里允许导航到后端域名:
import { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { appId: '你的AppID', appName: '你的App名称', webDir: 'www', server: { allowNavigation: ['your_domain.com'] } }; export default config;
内容的提问来源于stack exchange,提问作者Charles
相关产品推荐
相关产品推荐

