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

React中使用Cookie实现RBAC权限控制的问题求助

问题描述

尝试在React应用中用Cookie实现基于角色的访问控制(RBAC),遇到两个核心问题:

  1. 登录后Cookie已正确存入浏览器,但后端check-role接口接收不到该Cookie,导致鉴权失败。
  2. 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无法传递到后端的排查与修复

  1. 必须安装并启用cookie-parser中间件
    后端要解析req.cookies,必须在Express中配置cookie-parser:

    npm install cookie-parser
    

    在主入口文件(如app.js)中添加:

    const cookieParser = require('cookie-parser');
    app.use(cookieParser());
    

    这是最可能导致req.cookies为空的核心原因。

  2. 配置正确的CORS规则
    若前后端跨域(端口不同),后端需配置CORS允许携带凭证,且不能使用通配符*作为origin:

    const cors = require('cors');
    app.use(cors({
      origin: "http://localhost:你的前端端口", // 比如3001
      credentials: true
    }));
    
  3. Cookie的domain属性适配
    本地开发时,可显式设置Cookie的domain为localhost,确保浏览器能正确发送:

    res.cookie("auth_cookie", token, {
      httpOnly: true,
      secure: false,
      maxAge: 24 * 60 * 60 * 1000,
      domain: "localhost" // 添加这一行
    })
    
  4. 修正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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 12:07:38