401 在 MERN 应用程序中为子域配置 NGINX 后出现未经授权的错误(未设置 JWT cookie)

问题描述 投票:0回答:1
我使用 DigitalOcean、Nginx 和 PM2 部署了 MERN 应用程序。该应用程序在服务器的 IP 上运行良好,但在为子域配置 NGINX(后端为

api.example.com

,客户端为 
example.com
)后,我开始在经过 JWT 验证的 API 请求上收到 
401 Unauthorized
 错误。我认为 JWT (
access_token_client
) 的 cookie 没有在浏览器中设置。另外,当我检查 Chrome 开发者工具 > 应用程序 > 存储 > Cookies > 
www.example.com 时,access_token_client
 不存在。

首先,我尝试使用

credentials: true

 在我的 server/index.js 中配置 CORS。我还允许起源 
http://example.com
http://www.example.com
http://admin.example.com

我还编辑了登录后端 API 控制器,因为这是设置 cookie 并将 JWT 签名给用户的地方:

export const signin = async (req, res, next) => { try { const user = await User.findOne({ username: req.body.username }) if (!user) return next(createError(404, "User not found!")) const isCorrect = await bcrypt.compare(req.body.password, user.password) if (!isCorrect) return next(createError(400, "Wrong username or password!")) const token = jwt.sign({id: user._id}, process.env.JWT) const {password, ...others} = user._doc res.cookie("access_token_client", token, { httpOnly: true, secure: false, // Set to false because I'm on HTTP not HTTPS sameSite: 'none', domain: '.example.com', maxAge: 24 * 60 * 60 * 1000 // 24 hours }).status(200) .json(others) console.log('Set-Cookie header:', res.getHeader('Set-Cookie')); } catch(err) { next(err) } }
然后我编辑了服务器的 NGINX 配置:

server { listen 80; server_name api.example.com; location / { proxy_pass http://127.0.0.1:8800; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header Cookie $http_cookie; add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since'; add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH'; } }
在我的前端,特别是在 Login.jsx 中,我还在 axios 实例中添加了 

withCredentials: true

,如下所示:

const axiosInstance = axios.create({ baseURL:process.env.REACT_APP_API_URL, // http://api.example.com/api withCredentials: true }); const handleLogin = async (e) => { e.preventDefault(); dispatch(loginStart()); try { if (!username || !password) { throw new Error("Username and password are required"); } const res = await axiosInstance.post("/auth/signin", {username, password}); dispatch(loginSuccess(res.data)); navigate('/dashboard'); } catch(err) { dispatch(loginFailure()); setError(err.response ? err.response.data.message : err.message); } }
这是一个具有 verifyToken 中间件的 API 示例:

控制器:

export const getProgresses = async (req, res, next) => { const { userId } = req.params; if (userId !== req.user.id) { return next(createError(403, "Authorization error!")); } try { // Find all progress records for the current user const progresses = await Progress.find({ userId }) .populate({ path: 'unitId', select: 'title image', }) .populate({ path: 'moduleId', select: 'title courseId', populate: { path: 'courseId', select: 'title', } }) .sort({ updatedAt: -1 }); // Map progresses to include courseTitle from moduleId.courseId const progressesWithCourseTitle = progresses.map(progress => ({ ...progress.toObject(), courseTitle: progress.moduleId.courseId.title })); res.status(200).json(progressesWithCourseTitle); } catch (error) { next(error); } };
路线:

router.get('/:userId', verifyToken, getProgresses)
然后这是我的 verifyToken.js 中间件:

import jwt from 'jsonwebtoken' import { createError } from './error.js' export const verifyToken = (req, res, next) => { const token = req.cookies.access_token_client if (!token) { console.log('No token found in cookies or headers'); return next(createError(401, "You are not authenticated!")) } console.log('Token found:', token); jwt.verify(token, process.env.JWT, (err, user) => { if(err) { console.log('Token verification failed:', err); return next(createError(403, "Invalid token!")) } console.log('Token verified successfully. User:', user); req.user = user next() }) }
我能够登录/登录我的网络应用程序。因为我的登录后端 API 中有这个 

console.log('Set-Cookie header:', res.getHeader('Set-Cookie'));

,所以当我在服务器中 
pm2 logs
 时,我能够看到令牌。但每当我发出 API 请求并首先验证令牌的中间件时,我都会收到 401 未经授权的错误。经过检查,我认为收到此错误的原因是因为它首先没有要验证的令牌。在后端的
verifyToken
中间件中,找不到cookie(
req.cookies
为空)。

什么可能导致浏览器中未设置 JWT cookie?任何帮助将不胜感激!谢谢!

reactjs express nginx cookies jwt
1个回答
0
投票
解决了!

我的前端和后端位于不同的域,现代浏览器需要跨域 cookie 的“安全”标志。仅当域(前端和后端)通过 HTTPS(而非 HTTP)提供服务时,才能使用“安全”标志。因此,通过 HTTPS 为我的域名提供服务最终解决了我的问题。

© www.soinside.com 2019 - 2024. All rights reserved.