React中使用Cookie实现RBAC权限控制的问题求助
问题描述
尝试在React应用中用Cookie实现基于角色的访问控制(RBAC),遇到两个核心问题:
- 登录后Cookie已正确存入浏览器,但后端
check-role接口接收不到该Cookie,导致鉴权失败。 - AuthContext中的
useQuery会在应用全程触发查询,希望仅在登录成功后才调用接口获取角色信息。
计划通过Context存储角色信息,实现受保护路由和组件内权限控制,以后端返回的especialidad作为授权依据。
相关代码片段
登录时Cookie创建逻辑(后端)
const token = jwt.sign( { medicoInfo: { username: medico.username, especialidad: medico.especialidad, }, }, jwtSecret, { expiresIn: "1d", } ); res.cookie("auth_cookie", token, { httpOnly: true, secure: false, // 本地开发环境设置为false maxAge: 24 * 60 * 60 * 1000 }) res.json({token});
前端AuthContext实现
const AuthContext = createContext<string[] | undefined>(undefined); export const AuthContextProvider = ({children} :{children: ReactNode})=>{ const {data:roles} = useQuery({ queryFn: ()=> fetchRole(), queryKey: ["roles"], }) const userRoles = roles || []; return( <AuthContext.Provider value={userRoles}> {children} </AuthContext.Provider> ) } export const useAuthContext = ()=>{ const context = useContext(AuthContext); return context; }
前端API请求函数
export const fetchRole = async ():Promise<string[]>=>{ const response = await fetch("http://localhost:3000/api/auth/check-role",{ credentials: "include", }); if (!response.ok) { throw new Error("Something went wrong..."); } return response.json(); }
后端check-role路由
authRoutes.get('/check-role', verifyToken, async ( req:Request, res:Response)=>{ res.status(200).send({userRole: req.userInfo.especialidad}); })
VerifyToken中间件
declare global { namespace Express { interface Request { userInfo: { username: string, especialidad: string[], } } } } const verifyToken = (req: Request, res: Response, next: NextFunction) => { console.log(req.cookies); const token = req.cookies["auth_cookie"]; if (!token) { return res.status(401).json({message: "Unauthorized"}); } try { const decoded = jwt.verify(token, process.env.JWT_SECRET as string); req.userInfo = (decoded as JwtPayload).userInfo; next(); } catch (error) { return res.status(401).json({message: "Unauthorized"}); } }
问题解决方法
一、Cookie无法传递到后端的排查与修复
必须安装并启用
cookie-parser中间件
后端要解析req.cookies,必须在Express中配置cookie-parser:npm install cookie-parser在主入口文件(如
app.js)中添加:const cookieParser = require('cookie-parser'); app.use(cookieParser());这是最可能导致
req.cookies为空的核心原因。配置正确的CORS规则
若前后端跨域(端口不同),后端需配置CORS允许携带凭证,且不能使用通配符*作为origin:const cors = require('cors'); app.use(cors({ origin: "http://localhost:你的前端端口", // 比如3001 credentials: true }));Cookie的domain属性适配
本地开发时,可显式设置Cookie的domain为localhost,确保浏览器能正确发送:res.cookie("auth_cookie", token, { httpOnly: true, secure: false, maxAge: 24 * 60 * 60 * 1000, domain: "localhost" // 添加这一行 })修正JWT解码的字段名
登录时JWT的payload是medicoInfo,但中间件中尝试赋值req.userInfo = (decoded as JwtPayload).userInfo,字段名不匹配,应改为:req.userInfo = (decoded as JwtPayload).medicoInfo;
二、控制Context查询仅在登录后触发
修改AuthContext,添加登录状态管理,通过useQuery的enabled选项控制查询时机:
const AuthContext = createContext<{ userRoles: string[], isLoggedIn: boolean, setIsLoggedIn: (value: boolean) => void }>({ userRoles: [], isLoggedIn: false, setIsLoggedIn: () => {} }); export const AuthContextProvider = ({children} :{children: ReactNode})=>{ const [isLoggedIn, setIsLoggedIn] = useState(false); const {data:roles} = useQuery({ queryFn: ()=> fetchRole(), queryKey: ["roles"], enabled: isLoggedIn, // 仅当isLoggedIn为true时触发查询 refetchOnMount: false, // 可选:组件重新挂载时不自动重查 refetchOnWindowFocus: false // 可选:窗口聚焦时不自动重查 }) const userRoles = roles || []; return( <AuthContext.Provider value={{userRoles, isLoggedIn, setIsLoggedIn}}> {children} </AuthContext.Provider> ) } export const useAuthContext = ()=>{ const context = useContext(AuthContext); return context; }
然后在登录成功的逻辑中,调用setIsLoggedIn(true)触发角色查询:
// 示例登录成功后的处理 const handleLogin = async () => { const res = await fetch("/api/login", { method: "POST", credentials: "include", headers: {"Content-Type": "application/json"}, body: JSON.stringify(loginData) }); if (res.ok) { const { setIsLoggedIn } = useAuthContext(); setIsLoggedIn(true); // 触发角色查询 } }
内容的提问来源于stack exchange,提问作者yzkael
相关产品推荐
相关产品推荐

