【发布时间】:2022-01-05 14:03:59
【问题描述】:
我对 React 还不是很有经验,并且一直在尝试解决保护特定路由免受身份验证的问题。
为此,我需要实现一个 HOC 组件,特别是“PrivateRoute”组件。 一些主要的概括:
-
我正在使用 React 17.0.2 进行开发,然后是 react-router-dom 6.2.1
-
我需要验证令牌在 Redis 服务器(在云中)上是否存在并验证它。
该项目分为两个“模块”,一个在 React 中用于前端,一个在 node js/express 中,它暴露了服务器端逻辑。
在前端模块中,路由实现如下:
return (<Router>
<div className="App">
<nav className="navbar navbar-expand-lg navbar-light fixed-top">
<div className="container">
<Link className="navbar-brand" to={"/"}>My Site</Link>
<div className="collapse navbar-collapse" id="navbarTogglerDemo02">
<ul className="navbar-nav ml-auto">
<li className="nav-item">
<Link className="nav-link" to={"/sign-in"}>Login</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to={"/sign-up"}>Sign up</Link>
</li>
</ul>
</div>
</div>
</nav>
<Routes>
<Route exact path='/' element={<PrivateRoute><Home /></PrivateRoute>} />
<Route path="/sign-in" element={<Login />} />
<Route path="/sign-up" element={<SignUp />} />
<Route path="*" Component={<Login/>} status={403}/>
</Routes>
</div></Router>
如您所见,例如,我希望 Home 组件受到保护,因此我实现了用于包装 Home 组件的 PrivateRoute 组件。
PrivateRoute 组件的实现必须验证 localStorage 中存在的任何 jwt 令牌,并将其传递给 node/express 模块公开的 HTTP 验证服务。令牌通过 Authorization Bearer 标头发送到 http 服务。
从 localStorage 检索并发送到验证服务的逻辑是通过 useEffect (() => {}, []) 实现的。它里面定义了异步函数,所以你可以用await进行axios调用。该函数总是从 useEffect 的主体中调用。但是,我不明白为什么更新用 useState 创建的状态变量似乎没有正确更新(同步问题?)。如果 Home 组件验证正确(在三元运算符中,home 由 props.children 表示),而不是重定向到登录页面,这似乎不会触发渲染更新。
下面我汇报一下 PrivateRoute 的实现:
export const PrivateRoute = (props) => {
console.log('props',props);
const [tokenValid, setTokenValid] = useState('');
useEffect(() => {
const checkRedisToken = async () => {
console.log('Access localStorage');
const ni_token = localStorage.getItem('ni_token');
console.log('Returned localStorage');
const config = { headers: { 'Authorization': `Bearer ${ni_token}` } };
console.log('Call axios');
const response = await axios.get('http://localhost:5000/identity/verifytoken', config);
const data = response.data;
console.log('After axios ', data);
setTokenValid(response.data);
}
checkRedisToken();
console.log('tokenValid', tokenValid);
}, []);
return (
tokenValid !== '' ?
props.children :
<Navigate to="/sign-in" />
)
}
提前感谢您帮助理解我的错误。
非常感谢
【问题讨论】:
-
console.log('tokenValid', tokenValid);不会记录新的tokenValid值,因为 React 状态更新不是立即的。还有checkRedisToken是async,你不会在等待它。但状态仍应更新,组件应重新渲染。如果您发布控制台输出可能会有所帮助。 -
@tromgy 谢谢你的回复。是的你是对的。调用是异步的,所以我看不到日志的价值。但是,我会期待一个新的重新渲染。同时,阅读了一些类似的帖子,我通过引入中间状态来更改代码,这似乎有效。我如何共享代码并一起评论它?我会首先回答吗?
-
您可以尝试在代码和框/stackblitz 等中创建一个最小的可重现示例。因为我们都同意,只要设置了
tokenValid状态,渲染仍然应该发生。 -
嗨@tromgy,为简洁起见,我将用我目前的解决方案回复我的第一篇文章。该解决方案是网络研究和一些以前的类似帖子的结果。讨论解决方案以解释 React 的逻辑和操作对我会有所帮助,即使是那些最终发现自己在未来阅读此消息线程的人。
标签: reactjs async-await jwt authorization react-router-dom