Laravel iframe无法存储Cookie:Safari适配及LocalStorage替代方案
一、让Safari存储iframe中第三方站点Cookie的可行方案
- 使用Storage Access API:这是Safari官方适配第三方Cookie限制的方案,必须通过用户主动交互(如点击按钮)触发权限请求。在b.com的登录逻辑中加入以下处理:
document.getElementById('login-trigger').addEventListener('click', async () => { try { const accessGranted = await document.requestStorageAccess(); if (accessGranted) { // 权限获取成功后执行登录请求,此时Cookie可正常存储 await fetch('/login', { method: 'POST', credentials: 'include' }); } } catch (err) { // 权限请求失败时,提示用户手动授权或切换方案 } });
- 配置站点关联(Apple App Site Association):若a.com和b.com同属一个主体,可通过配置AASA文件让Safari判定二者为关联站点,从而允许第三方Cookie。需在b.com根目录放置
apple-app-site-association文件,包含a.com的域名配置,并在苹果开发者后台完成关联域名备案。 - 第一方上下文跳转登录:先引导用户从iframe跳转至b.com的独立登录页面(第一方环境),登录完成后再跳转回a.com的iframe。此方式能确保Cookie正常写入,仅用户体验略有折损。
二、Laravel改用LocalStorage实现用户认证
若上述Cookie方案无法满足需求,可通过令牌式认证替代Cookie,将令牌存储在LocalStorage中:
1. 配置Laravel Sanctum令牌认证
- 安装并初始化Sanctum:
composer require laravel/sanctum php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider" php artisan migrate
- 修改
config/auth.php,将API守卫驱动设为Sanctum:
'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'sanctum', 'provider' => 'users', ], ],
2. 编写登录接口返回令牌
在登录控制器中,验证用户后生成并返回PlainText令牌:
use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; public function login(Request $request) { $validated = $request->validate([ 'email' => 'required|email', 'password' => 'required', ]); if (!Auth::attempt($validated)) { return response()->json(['msg' => '登录失败'], 401); } $token = Auth::user()->createToken('iframe-auth')->plainTextToken; return response()->json(['token' => $token]); }
3. 前端存储令牌到LocalStorage
登录成功后将令牌存入LocalStorage:
fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: 'user@example.com', password: 'xxx' }) }) .then(res => res.json()) .then(data => localStorage.setItem('auth_token', data.token));
4. 后续请求携带令牌
所有需要认证的请求,在请求头中携带令牌:
fetch('/api/user', { headers: { 'Authorization': `Bearer ${localStorage.getItem('auth_token')}` } }) .then(res => res.json()) .then(userData => console.log(userData));
5. 注销逻辑处理
注销时删除LocalStorage令牌,并在后端撤销对应令牌:
// 前端清除令牌 localStorage.removeItem('auth_token'); // 后端注销接口 public function logout(Request $request) { $request->user()->currentAccessToken()->delete(); return response()->json(['msg' => '注销成功']); }
内容的提问来源于stack exchange,提问作者Mohammad Salehi
相关产品推荐
相关产品推荐

