Flutter中Dio拦截器对接Laravel Sanctum的CSRF Token不匹配问题
解决Flutter Dio对接Laravel Sanctum时CSRF Token不匹配问题
1. 修正Laravel跨域配置(核心)
Laravel的config/cors.php必须正确配置,禁止用通配符*作为允许源,同时开启凭证支持:
return [ 'paths' => ['api/*', 'sanctum/csrf-cookie'], 'allowed_methods' => ['*'], 'allowed_origins' => ['http://localhost:8080', '你的Flutter应用实际域名'], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => [], 'max_age' => 0, 'supports_credentials' => true, // 必须设为true ];
同时更新.env文件的状态域配置:
SANCTUM_STATEFUL_DOMAINS=localhost,localhost:8080,你的实际域名
2. 让Dio自动管理Cookie
Dio默认不会自动保存和携带Cookie,需要引入dio_cookie_manager和cookie_jar包,配置CookieJar:
import 'package:dio/dio.dart'; import 'package:dio_cookie_manager/dio_cookie_manager.dart'; import 'package:cookie_jar/cookie_jar.dart'; // 初始化Dio并配置CookieJar final dio = Dio(); final cookieJar = CookieJar(); dio.interceptors.add(CookieManager(cookieJar)); // 再添加你的CSRF拦截器 dio.interceptors.add(CsrfTokenInterceptor(dio, cookieJar));
关键原因:Sanctum验证CSRF时,需要同时校验请求头的X-XSRF-TOKEN和Cookie中的XSRF-TOKEN,只带请求头无法通过验证。
3. 简化拦截器逻辑
无需手动解析响应头的Cookie,直接从CookieJar中读取已保存的XSRF-TOKEN:
import 'dart:io'; import 'package:dio/dio.dart'; import 'package:cookie_jar/cookie_jar.dart'; class CsrfTokenInterceptor extends Interceptor { final Dio dio; final CookieJar cookieJar; CsrfTokenInterceptor(this.dio, this.cookieJar); @override Future<void> onRequest(RequestOptions options, RequestInterceptorHandler handler) async { List<String> methods = ['POST', 'PUT', 'DELETE', 'PATCH']; if (methods.contains(options.method)) { // 先获取CSRF Cookie并自动保存到CookieJar await dio.get('/sanctum/csrf-cookie'); // 从CookieJar中取出XSRF-TOKEN final cookies = await cookieJar.loadForRequest(Uri.parse(dio.options.baseUrl)); final xsrfToken = cookies.firstWhere((cookie) => cookie.name == 'XSRF-TOKEN', orElse: () => null); if (xsrfToken != null) { options.headers['X-XSRF-TOKEN'] = Uri.decodeFull(xsrfToken.value); } } handler.next(options); } }
4. 验证请求的Cookie是否正确携带
在拦截器中打印请求的Cookie头,确认包含XSRF-TOKEN和laravel_session:
@override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { print('Request Cookie: ${options.headers[HttpHeaders.cookieHeader]}'); // 其他逻辑... }
如果Cookie头为空,说明Dio的CookieJar未正确配置。
5. 对齐Postman与Flutter的请求参数
对比两者的请求信息,确保:
- 请求的域名/端口完全一致(避免映射域名和本地地址混用)
X-XSRF-TOKEN的值解码后与Postman一致- 请求头中携带了完整的
Cookie字段
内容的提问来源于stack exchange,提问作者raw.nato
相关产品推荐
相关产品推荐

