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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 20:39:54