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

MERN应用PC端正常移动端登录未授权问题排查

问题描述

我开发的MERN Web应用在PC端运行正常,但在移动端登录时出现「未授权访问」错误,核心表现是Cookie未被正确设置。后端部署在Render平台,前端部署在Vercel平台。

请问这是因为使用req.cookies.token导致的吗?是否应该改用req.headers.authorization?

以下是后端server.js代码:

import cors from 'cors';
import express from 'express';
import authRoutes from './routes/auth.route.js';
import userRoutes from './routes/user.route.js';
import postRoutes from './routes/post.route.js';
import notificationRoutes from './routes/notification.route.js';
import dotenv from 'dotenv';
import connectToDb from './config/db.config.js';
import cookieParser from 'cookie-parser';
import { v2 as cloudinary } from 'cloudinary';
import rateLimit from 'express-rate-limit';

dotenv.config();
cloudinary.config({
    cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
    api_key: process.env.CLOUDINARY_API_KEY,
    api_secret: process.env.CLOUDINARY_API_SECRET,
});

const app = express();
const port = process.env.PORT || 4000;

const allowedOrigins = [
  "http://localhost:3000",
  process.env.CLIENT_URL,
];

app.use(
  cors({
    origin: allowedOrigins,
    credentials: true,
    methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    allowedHeaders: ["Content-Type", "Authorization", 'Cookie'],
  })
);
app.use(express.json({ limit: '5mb' }));
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());


let limiter = rateLimit({
    max: 500,
    windowMs: 60 * 60 * 1000,
    message: {status: 429, message:"Too many requests from this IP, please try again after an hour"},
    validate: {xForwardedForHeader: false}
});
app.use('/api', limiter);
app.use('/api/auth', authRoutes);
app.use('/api/users', userRoutes);
app.use('/api/posts', postRoutes);
app.use('/api/notifications', notificationRoutes);


app.listen(port, () => {
    console.log(`Server is listening to port ${port}`);
    connectToDb();
});
问题分析与解决方案

1. 移动端Cookie未设置的核心原因

不是req.cookies.token本身的问题,而是Cookie的配置属性不符合移动端浏览器的安全规则:

  • 跨域场景下,移动端浏览器对Cookie的SameSite、Secure属性要求更严格。如果后端设置Cookie时没指定SameSite: 'None'和Secure: true,移动端浏览器会拒绝存储Cookie(尤其是iOS Safari、Chrome移动端)。
  • 你的CORS配置已经开启了credentials: true,但如果Cookie本身的属性不达标,移动端依然不会保存。

2. 是否需要改用req.headers.authorization?

两种方案都可行,各有优劣:

  • Cookie方案:只要修正Cookie配置就能继续使用,适合需要自动携带凭证的场景(比如页面跳转时自动传Cookie)。
  • Authorization头方案:需要前端手动在每个请求的headers里添加Bearer <token>,不受Cookie跨域限制,适配性更强,但需要前端统一处理请求头。

3. 具体修复步骤

方案一:修复Cookie配置(推荐继续使用Cookie)

找到后端设置Cookie的代码(比如登录接口里的res.cookie()),补充以下属性:

res.cookie('token', token, {
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production', // 生产环境必须开启Secure
  sameSite: process.env.NODE_ENV === 'production' ? 'None' : 'Lax', // 跨域场景必须设为None
  maxAge: 7 * 24 * 60 * 60 * 1000 // 按需设置过期时间
});

注意:SameSite: None必须和Secure: true一起使用,否则浏览器会忽略该Cookie。

方案二:切换到Authorization头

  • 后端:修改鉴权逻辑,从req.headers.authorization中提取token:
// 示例鉴权中间件
const authMiddleware = (req, res, next) => {
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ message: '未授权访问' });
  }
  const token = authHeader.split(' ')[1];
  // 后续验证token逻辑...
  next();
};
  • 前端:登录成功后把token存在localStorage或sessionStorage,然后在请求拦截器里统一添加Authorization头:
// 示例Axios拦截器
axios.interceptors.request.use(config => {
  const token = localStorage.getItem('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

额外检查点

  • 确认process.env.CLIENT_URL在生产环境中是正确的Vercel域名(必须是HTTPS),否则CORS会失效。
  • 移动端测试时确保网络是HTTPS环境,HTTP下Secure属性的Cookie无法被存储。

内容的提问来源于stack exchange,提问作者Dev-Lo.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 01:19:54