NextJS / React - 如何避免对服务器的多次请求?
NextJS / React - how to avoid multiple requests to server?
我正在写一个小项目,其中我对如何设计前端授权流程有疑问。
堆栈是:Next.js/Express/MDB
这是授权问题:在我的应用程序中,有些页面应该只提供给教师。
当应用程序安装时,我会调用我的后端检查存储的 cookie 并授权用户。返回的用户存储在上下文中。
authContext.js
useEffect(() => {
checkUserLoggedIn();
}, []);
...
const checkUserLoggedIn = async () => {
const res = await fetch(`${process.env.NEXT_PUBLIC_CLIENT}/user`);
const data = await res.json();
if (res.status === 200) {
setUser(data.user);
} else {
setUser(null);
}
};
效果很好。
但现在是我挣扎的部分。
受保护的页面由一个组件包装,该组件再次检查用户是否 a) 已通过身份验证和 b) 已获得授权。
wrapInstructor.js
const CheckInstructor = ({ token, children }) => {
const [ok, setOk] = useState(false);
const [login, setLogin] = useState(null);
useEffect(async () => {
try {
const user = await fetch(
`${process.env.NEXT_PUBLIC_APIURL}/me`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const { data, error } = await user.json();
if (error) {
toast.error("Auf diese Seite können nur eingeloggte User zugreifen");
setLogin(false);
}
if (data && data.role.includes("INSTRUCTOR")) {
setOk(true);
setLogin(true);
}
} catch (error) {
toast.error(error);
setLogin(false);
}
}, []);
return !ok ? (
<>{login === false ? <NotLoggedIn /> : <Spinner />}</>
) : (
<>{children}</>
);
};
export default CheckInstructor;
现在问题来了:
当用户将应用程序安装到受保护的路径时,应用程序会同时触发两个身份验证请求。
第一个获得有效响应(来自上下文的请求)。包装器中的第二个获得 304 状态代码,表示自上次请求以来响应没有更改。
但由于包装器需要有效响应,因此受保护页面的内容将不会显示。
我该如何解决这个问题? (注意:我处于开发模式,从本地主机测试)
我的想法是:
包装器组件不会再次调用服务器 - 上下文中的用户是唯一的真实来源,包装器只检查已存储的用户 --> 问题:这是一个安全做法?用户是否可以操纵商店(React Context 或 Redux),这会使我的应用不安全?
如果状态代码为 304 并且用户已存储在上下文中,则在包装器组件中还会显示子组件
在后端编写另一个端点,以便将两个请求发送到不同的路由(我会考虑这种不好的做法,因为 DRY)
我有点迷路了 - 你能帮我理清思绪吗?
非常感谢!
无需访问同一个端点两次来检查用户是否有权访问特定页面。您在身份验证上下文中存储的内容就足够了。只要确保在角色或权限发生变化时更新值即可。
考虑到您的安全问题,您不应认为任何 客户端应用程序是安全的。即使你在每个受保护的页面上添加一个实际的端点调用,仍然有一种方法可以直接调用端点(curl,邮递员,你的名字)。
应该通过在 每个 受保护的 API 路由上引入授权检查来解决该问题。这样你就完全不用担心客户端损坏了。
我正在写一个小项目,其中我对如何设计前端授权流程有疑问。
堆栈是:Next.js/Express/MDB
这是授权问题:在我的应用程序中,有些页面应该只提供给教师。 当应用程序安装时,我会调用我的后端检查存储的 cookie 并授权用户。返回的用户存储在上下文中。
authContext.js
useEffect(() => {
checkUserLoggedIn();
}, []);
...
const checkUserLoggedIn = async () => {
const res = await fetch(`${process.env.NEXT_PUBLIC_CLIENT}/user`);
const data = await res.json();
if (res.status === 200) {
setUser(data.user);
} else {
setUser(null);
}
};
效果很好。 但现在是我挣扎的部分。 受保护的页面由一个组件包装,该组件再次检查用户是否 a) 已通过身份验证和 b) 已获得授权。
wrapInstructor.js
const CheckInstructor = ({ token, children }) => {
const [ok, setOk] = useState(false);
const [login, setLogin] = useState(null);
useEffect(async () => {
try {
const user = await fetch(
`${process.env.NEXT_PUBLIC_APIURL}/me`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const { data, error } = await user.json();
if (error) {
toast.error("Auf diese Seite können nur eingeloggte User zugreifen");
setLogin(false);
}
if (data && data.role.includes("INSTRUCTOR")) {
setOk(true);
setLogin(true);
}
} catch (error) {
toast.error(error);
setLogin(false);
}
}, []);
return !ok ? (
<>{login === false ? <NotLoggedIn /> : <Spinner />}</>
) : (
<>{children}</>
);
};
export default CheckInstructor;
现在问题来了: 当用户将应用程序安装到受保护的路径时,应用程序会同时触发两个身份验证请求。
第一个获得有效响应(来自上下文的请求)。包装器中的第二个获得 304 状态代码,表示自上次请求以来响应没有更改。
但由于包装器需要有效响应,因此受保护页面的内容将不会显示。
我该如何解决这个问题? (注意:我处于开发模式,从本地主机测试)
我的想法是:
包装器组件不会再次调用服务器 - 上下文中的用户是唯一的真实来源,包装器只检查已存储的用户 --> 问题:这是一个安全做法?用户是否可以操纵商店(React Context 或 Redux),这会使我的应用不安全?
如果状态代码为 304 并且用户已存储在上下文中,则在包装器组件中还会显示子组件
在后端编写另一个端点,以便将两个请求发送到不同的路由(我会考虑这种不好的做法,因为 DRY)
我有点迷路了 - 你能帮我理清思绪吗?
非常感谢!
无需访问同一个端点两次来检查用户是否有权访问特定页面。您在身份验证上下文中存储的内容就足够了。只要确保在角色或权限发生变化时更新值即可。
考虑到您的安全问题,您不应认为任何 客户端应用程序是安全的。即使你在每个受保护的页面上添加一个实际的端点调用,仍然有一种方法可以直接调用端点(curl,邮递员,你的名字)。
应该通过在 每个 受保护的 API 路由上引入授权检查来解决该问题。这样你就完全不用担心客户端损坏了。