Axios无法将Access Token存入请求头的授权问题求助
授权请求头设置异常问题
登录流程可正常完成,refresh token已成功存入Cookie和数据库,但Axios无法将access token写入请求头。浏览器网络面板完全看不到Authorization请求头,尝试通过axios.default.headers设置全局请求头也无效;执行console.log(axios.defaults.headers.common)能在控制台看到已设置的token,但实际请求中就是不携带。
前端Login组件代码
export default function Login () { const [state, setState] = useContext(UserContext); const navigate = useNavigate() const { register, handleSubmit, formState: { errors } } = useForm<Inputs>({ defaultValues: loginValues, mode: 'onTouched', criteriaMode: 'firstError', reValidateMode: 'onBlur' }); const onSubmit: SubmitHandler<Inputs> = async (data) => { try { const phone_num = data.phone_num; // eslint-disable-line const password = data.password; const { data: login } = await axios.post("auth/login_admin", { phone_num, password }, { withCredentials: true } ); axios.defaults.headers.common['Authorization'] = `Bearer ${login['token']}`; setState({ data: { id: login.data.id, isAdmin: login.data.isAdmin, user_type: login.data.user_type }, loading: false, error: null }) navigate("/council"); } catch (err: any) { setState({ data: null, loading: false, error: err.message }) console.log(err) } }; return ( <> <Box sx={{ display: 'center', justifyContent: 'center', alignItems: 'center', width: '100vw', height: '100vh' }} > <Box sx={{ height: 'auto', width: '40%', display: 'center', justifyContent: 'center', alignItems: 'center' }} component='form' > <TextField margin="normal" fullWidth variant='filled' id="phone_num" label="Phone Number" {...register("phone_num", { required: 'Phone Number is required', pattern: { value: phonePattern, message: 'Please enter a valid phone number' } })} autoFocus error={!!errors?.phone_num} /> {errors.phone_num && (<Typography variant='body2' mt={1} component='span' sx={{ color: 'red', textAlign: 'left' }} >{errors.phone_num?.message}</Typography>) } <FormControl sx={{ mt: 3, width: '100%' }} variant="filled"> <InputLabel htmlFor="filled-adornment-password">Password</InputLabel> <FilledInput id="filled-adornment-password" // type={passType} {...register("password", { required: 'Password is required', pattern: { value: passwordPattern, message: 'Password cannot be less than 8 characters' } })} error={!!errors?.password} /> </FormControl> <Button type="submit" onClick={handleSubmit(onSubmit)} // eslint-disable-line > Sign In </Button> </Box> </Box> </> ) }
后端相关代码
Service层代码
export const adminLogin = async (res: Response, body: AuthType, next: NextFunction) => { let transaction; try { transaction = await sequelize.transaction(); const { phone_num, password } = body; const user = await Admin.findOne({ where: { phone_num } }, { transaction }); if (!user || user === null) { return next(new AppError("Invalid phone number or password", BAD_REQUEST)); } const isMatch = verifyBcryptPassword(password, user.password); if (!isMatch) { return next(new AppError("Invalid phone number or password", BAD_REQUEST)); } await transaction.commit(); const { token, refreshToken } = await jwtGenerator(user.dataValues); res.cookie('refreshToken', refreshToken, { httpOnly: true, maxAge: 7 * 24 * 60 * 60 * 1000 //7 days }); return { user, token }; } catch (e: any) { if (transaction) { await transaction.rollback(); } return next(new AppError(e, BAD_REQUEST)); } };
Controller层代码
const login_admin = async (req: Request, res: Response, next: NextFunction) => { try { const validate = authValidator.authLogin(req.body); if (validate.error) { return next(new AppError(validate.error.message, BAD_REQUEST)); } const result = await adminLogin(res, req.body, next); const user = result?.user.dataValues; const access = result?.token; return res.status(OK).json({ status: "success", message: "Login was successful.", token: access, data: { id: user.id, isAdmin: user.isAdmin, user_type: user.user_type } }); } catch (error: any) { return next(new AppError(error.message, BAD_REQUEST)); } };
问题排查与解决方法
1. 检查Axios实例一致性
如果项目中使用了自定义Axios实例(通过axios.create()创建),直接修改全局axios.defaults不会作用于该实例。解决:
- 确保所有请求复用同一个实例,并修改该实例的headers:
// 示例:创建全局Axios实例 const api = axios.create({ baseURL: '/api' }); // 登录成功后设置实例headers api.defaults.headers.common['Authorization'] = `Bearer ${login.token}`;
2. 持久化Token并添加请求拦截器
全局设置的headers在页面刷新后会丢失,且路由跳转可能导致状态重置。正确做法是:
- 将Token存入
localStorage,并通过请求拦截器自动注入:
// 项目入口文件添加拦截器 axios.interceptors.request.use( config => { const token = localStorage.getItem('accessToken'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, error => Promise.reject(error) ); // 登录时存入Token const onSubmit = async (data) => { // ...登录请求逻辑 localStorage.setItem('accessToken', login.token); // 同步设置全局headers axios.defaults.headers.common['Authorization'] = `Bearer ${login.token}`; // ...其他逻辑 };
3. 验证后端CORS配置
后端必须允许Authorization请求头通过CORS,否则浏览器会自动移除该头。修改CORS配置:
const corsOptions = { origin: '你的前端域名', credentials: true, allowedHeaders: ['Content-Type', 'Authorization'] // 必须包含Authorization }; app.use(cors(corsOptions));
4. 确认代码执行顺序
确保axios.defaults.headers的设置在后续请求之前执行。可添加测试请求验证:
axios.defaults.headers.common['Authorization'] = `Bearer ${login.token}`; // 立即发起测试请求 axios.get('/api/test-endpoint').then(res => console.log('请求头已携带Token'));
内容的提问来源于stack exchange,提问作者Ayobami Ajibola
相关产品推荐
相关产品推荐

