Laravel Sanctum+Next.js页面刷新后Cookie丢失问题排查
我的应用后端基于Laravel(运行在127.0.0.1),前端基于Next.js(运行在localhost:3000)。用户完成授权后可以进入个人资料页,但刷新页面时Cookie会立即被删除(在localhost:3000创建的token Cookie显示黄色背景)。用Postman测试后端一切正常,相关配置代码如下:
.env配置
APP_URL=http://localhost:3000 SANCTUM_STATEFUL_DOMAINS=localhost SESSION_DRIVER=cookie
cors.php配置
'paths' => ['api/*', 'sanctum/csrf-cookie'], 'allowed_methods' => ['*'], 'allowed_origins' => ['http://localhost:3000'], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => [], 'max_age' => 0, 'supports_credentials' => true,
AuthController.php代码
class AuthController extends Controller { public function register(RegisterRequest $request) { $data = $request->validated(); $user = User::create([ 'name' => $data['name'], 'email' => $data['email'], 'password' => Hash::make($data['password']), ]); $token = $user->createToken('auth_token')->plainTextToken; $cookie = cookie('token', $token, 60 * 24); // 1 day return response()->json([ 'user' => new UserResource($user), ])->withCookie($cookie); } public function login(LoginRequest $request) { $data = $request->validated(); $user = User::where('email', $data['email'])->first(); if (!$user || !Hash::check($data['password'], $user->password)) { return response()->json([ 'message' => 'Email or password is incorrect!' ], 401); } $token = $user->createToken('auth_token')->plainTextToken; $cookie = cookie('token', $token, 60 * 24); // 1 day return response()->json([ 'user' => new UserResource($user), ])->withCookie($cookie); } public function logout(Request $request) { $request->user()->currentAccessToken()->delete(); $cookie = cookie()->forget('token'); return response()->json([ 'message' => 'Logged out successfully!' ])->withCookie($cookie); } public function user(Request $request) { return new UserResource($request->user()); } }
前端代码
AuthApi.js
import http from "./http"; export async function login(data) { return await http.post(`/login`, data) } export async function register(data) { return await http.post('register', data) } export async function logout() { return await http.post('/logout') } export async function user() { return await http.get('/user') }
http.js
import axios from 'axios' const axiosInstance = axios.create({ baseURL: `${process.env.NEXT_PUBLIC_BECK_APP_URL}`, withCredentials: true, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, }) export default axiosInstance
LoginPage.js
'use client'; import Button from '@/components/UI/Button'; import AlertError from '@/components/UI/AlertError'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faUser } from '@fortawesome/free-regular-svg-icons'; import Link from 'next/link'; import { useState } from 'react'; import { useAuth } from '@/context/AuthContext'; import { login } from '@/lib/AuthApi'; import { useRouter } from 'next/navigation'; const LoginPage = () => { const { setUser, csrfToken } = useAuth(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(null); const router = useRouter(); const handleSubmit = async e => { e.preventDefault(); setError(null); await csrfToken() try { const resp = await login({email, password}); if (resp.status === 200) { setUser(resp.data.user); router.push('/profile'); } } catch (error) { if (error.response.status === 422) { setError(error.response.data.message); } if (error.response.status === 401) { setError(error.response.data.message); } console.log(error) } } return ( <div className='xs:w-[95%] md:w-1/2 lg:w-1/3 my-10 text-center mx-auto py-10 border-t-4 border-myYellow bg-gray-900'> <form onSubmit={handleSubmit} className='max-w-md mx-auto text-myWhite px-5' > <h6 className='text-xl font-extrabold font-montserrat'> Авторизація </h6> <div className='py-3'> <FontAwesomeIcon icon={faUser} className='text-3xl bg-white p-5 rounded-full leading-none' /> </div> <div className='mb-4'> <input type='email' value={email} onChange={e => setEmail(e.target.value)} placeholder='Ваш логін' className={`block w-full bg-myDark border rounded-md border-myWhite text-myWhite text-[16px] p-2`} /> <input type='password' value={password} onChange={e => setPassword(e.target.value)} placeholder='Ваш пароль' className={`block w-full bg-myDark border rounded-md border-myWhite text-myWhite text-[16px] p-2 mt-4`} /> <div className='mt-2'> <AlertError error={error} /> </div> </div> <div type='submit'> <Button title='Увійти на сайт' className='w-full py-2' /> </div> <div className='flex justify-between mt-4 text-gray-300 text-[14px] decoration-dotted'> <div className='block'> <Link href='/signup'>Реєстрація</Link> </div> <div className='block'> <Link href='/forgot-password'>Забули пароль?</Link> </div> </div> </form> </div> ) }; export default LoginPage;
内容的提问来源于stack exchange,提问作者Bogdan
相关产品推荐
相关产品推荐

