跨微服务传递JWT Cookie遇401错误:Token缺失问题排查
跨微服务JWT令牌传递401问题
问题现象
直接将JWT令牌通过Cookie发送至http://localhost:8000/api/profile时可正常获取用户数据,但通过第二个微服务转发令牌时,收到401 Unauthorized错误,提示Token is missing。
错误日志
{ "status": 401, "statusText": "Unauthorized", "headers": { "date": "Sat, 22 Feb 2025 08:03:25 GMT", "server": "uvicorn", "content-length": "29", "content-type": "application/json" }, "data": { "detail": "Token is missing" } }
相关配置与代码
发送令牌的微服务(Node.js)CORS配置
app.set('trust proxy', true); app.use(cookieParser()); // CORS settings app.use(cors({ origin: 'http://localhost:5173', credentials: true, optionsSuccessStatus: 200 }));
接收令牌的微服务(FastAPI)CORS配置
app = FastAPI() origins = [ "http://localhost:5173" ] app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], )
微服务转发请求代码
const axios = require('axios'); const getUserProfile = async (token) => { try { const response = await axios.get('http://fast-api:8000/api/profile', { withCredentials: true, // Send cookies with the request }); return response.data; } catch (error) { console.error('Error fetching user profile:', error); if (error.response) { console.error('Response error data:', error.response.data); console.error('Response error status:', error.response.status); console.error('Response error headers:', error.response.headers); } else if (error.request) { console.error('Request error data:', error.request); } else { console.error('General error message:', error.message); } throw new Error('Failed to fetch user profile'); } };
发送端授权中间件
const authMiddleware = async (req, res, next) => { const token = req.cookies.access_token; console.log('Cookies:', req.cookies); console.log('Received token:', token); if (!token) { return res.status(401).json({message: 'Token is missing'}); } try { const userProfile = await getUserProfile(token); req.user = userProfile; next(); } catch (error) { console.error('Error in authMiddleware:', error); return res.status(401).json({ message: error.message, stack: error.stack, }); } };
FastAPI接收令牌代码
@router.get("/profile") def get_user(request: Request): print("Received headers:", request.headers) print("Received query parameters:", request.query_params) print("Received cookies:", request.cookies) token = request.cookies.get("access_token") print("Received token:", token) if not token: raise HTTPException(status_code=401, detail="Token is missing") return get_user_service(token)
核心问题
发送令牌的微服务日志显示已正确接收Cookie,但转发至接收令牌的微服务后,令牌无法被识别,返回401 Unauthorized错误。
问题原因
问题出在微服务转发请求时没有正确传递令牌:
getUserProfile函数接收了token参数,但代码中完全没有使用这个参数。withCredentials: true是给浏览器发送请求时用的,用于携带浏览器端的Cookie,但微服务之间的服务器端请求不存在浏览器Cookie上下文,这个配置无效。- 转发请求时没有将从客户端拿到的
access_token手动添加到请求的Cookie或Header中,导致FastAPI服务无法获取到令牌。
解决方案
修改getUserProfile函数,将令牌手动传递给FastAPI服务,有两种常用方式:
方式1:通过Cookie传递
const getUserProfile = async (token) => { try { const response = await axios.get('http://fast-api:8000/api/profile', { headers: { 'Cookie': `access_token=${token}` } }); return response.data; } catch (error) { // 错误处理逻辑不变 console.error('Error fetching user profile:', error); if (error.response) { console.error('Response error data:', error.response.data); console.error('Response error status:', error.response.status); console.error('Response error headers:', error.response.headers); } else if (error.request) { console.error('Request error data:', error.request); } else { console.error('General error message:', error.message); } throw new Error('Failed to fetch user profile'); } };
方式2:通过Authorization Header传递(更推荐)
如果可以修改FastAPI的令牌接收逻辑,改用Bearer Token方式更符合REST规范:
首先修改FastAPI代码:
from fastapi import HTTPException, Depends from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials security = HTTPBearer() @router.get("/profile") def get_user(credentials: HTTPAuthorizationCredentials = Depends(security)): token = credentials.credentials if not token: raise HTTPException(status_code=401, detail="Token is missing") return get_user_service(token)
然后修改转发函数:
const getUserProfile = async (token) => { try { const response = await axios.get('http://fast-api:8000/api/profile', { headers: { 'Authorization': `Bearer ${token}` } }); return response.data; } catch (error) { // 错误处理逻辑不变 console.error('Error fetching user profile:', error); if (error.response) { console.error('Response error data:', error.response.data); console.error('Response error status:', error.response.status); console.error('Response error headers:', error.response.headers); } else if (error.request) { console.error('Request error data:', error.request); } else { console.error('General error message:', error.message); } throw new Error('Failed to fetch user profile'); } };
内容的提问来源于stack exchange,提问作者Mikhail
相关产品推荐
相关产品推荐

