从cookie异步加载身份验证令牌时,React react-router-dom私有路由不起作用
Posted
技术标签:
【中文标题】从cookie异步加载身份验证令牌时,React react-router-dom私有路由不起作用【英文标题】:React react-router-dom private route not working when auth token is asynchronously loaded from cookies 【发布时间】:2020-10-18 08:56:54 【问题描述】:我有一个 react/redux 应用程序,使用“react-router-dom”进行路由。我在我的 App.js 中使用以下内容(标签是 react-bootstrap,以提供私有路由。当且仅当用户未登录时,预期行为将被重定向到 /login
(基于cookie)。实际行为是应用程序立即重定向到/login
,即使用户已登录。
class MainContainer extends Component
constructor(props)
super(props);
this.props.loadAuthCookie();
PrivateRoute = ( component: ChildComponent, ...rest ) =>
return (
<Route
...rest
render=(props) =>
if (!this.props.auth.loggedIn && !this.props.auth.authPending)
return <Redirect to="/login" />;
else
return <ChildComponent ...props />;
/>
);
;
render()
const PrivateRoute = this;
return (
<Router>
<Container fluid id="root">
<Header />
<Switch>
<Row className="pageContainer">
<Col>
<PrivateRoute exact path="/" component=HomeScreen />
<Route
exact
path="/clusters/"
component=clusterOverviewScreen
/>
<Route exact path="/login" component=LoginPage />
</Col>
</Row>
</Switch>
</Container>
</Router>
);
const mapStateToProps = (state) =>
return
auth: state.auth,
;
;
const mapDispatchToProps = (dispatch) =>
return
loadAuthCookie: () =>
return dispatch(loadAuthCookie());
,
;
;
const RootContainer = connect(
mapStateToProps,
mapDispatchToProps
)(MainContainer);
export default class App extends Component
render()
return (
<Provider store=store>
<RootContainer />
</Provider>
);
this.props.loadAuthCookie
函数调度一个 redux 操作,该操作拉取包含身份验证令牌(如果存在)的 cookie,并将其置于状态。
初始状态是
"authPending": false
"loggedIn": false
"authToken": null
变成:
"authPending": true
"loggedIn": false
"authToken": null
最后:
"authPending": false
"loggedIn": true
"authToken": TOKEN
我对反应比较陌生。我的猜测是,当 PrivateRoute 函数运行时,redux action 还没有设置状态,因此,PrivateRoute 组件重定向到登录页面。这个猜测是基于在私有路由中记录 props.auth.loggedIn
- 这会返回 false,但是当我重定向到的登录页面完成加载时,组件道具状态 this.props.loggedIn
是 true。我不知道如何不过要解决这个问题。
编辑:loadAuthCookie 操作:
export const loadAuthCookie = () => (dispatch) =>
dispatch(AuthReducer.setAuthPending());
try
const cookie = Cookies.get("token");
if (cookie)
dispatch(AuthReducer.setLoginSuccess(cookie));
catch (err)
console.log(err);
dispatch(AuthReducer.setLogout());
;
【问题讨论】:
你能不能也分享一下你的 loadAuthCookie 动作函数? 尝试将this.props.loadAuthCookie();
作为render的第一行而不是在构造函数中;之前const PrivateRoute = this;
@Hyetigran 完成。该建议似乎导致最大深度超出错误
这是因为函数在构造函数中被调用,然后被重新渲染并再次调用函数。只调用一次函数,应该使用componentDidMount生命周期方法componentDidMount() this.props.loadAuthCookie()
【参考方案1】:
PrivateRoute
看起来执行不正确。
它应该被设计为“等待”直到authPending
变为false
或loggedIn
变为true
。
但实际上,它要求它们都为真,才能不重定向到登录。因此,如果authPending: true
直到loggedIn:true
,则实施“等待”。
这是结果表。
也不要使用像!loggedIn && !authPending
这样可读性很差的条件,尤其是当你一直在工作时。我已经看过这个了,因为我无法被要求理解我所看到的。
<Route
...rest
render=(props) =>
if (this.props.auth.loggedIn)
return <ChildComponent ...props />;
else if (this.props.auth.authPending)
return <LoadingScreen/> // Or could simply div with text. Not different component
// Then state updates after x seconds and re-renders
else
return <Redirect to="/login" />;
/>
编辑:实际上我的逻辑错了,authPending & loggedIn
可以是 true
重定向到子元素,因为 !
逆运算符。
function test(first, second)
if (!first && !second)
console.log('login');
else
console.log('child');
test(true, true);
test(false,false);
test(true, false);
test(false, true);
输出:
child
login
child
child
看到还是想不通!;
【讨论】:
【参考方案2】:我认为托尼是对的;您可能需要在此组件的生命周期后期调用this.props.loadAuthCookie();
。
构造函数在(且仅当)组件被实例化时运行;而不是在安装或渲染时。构造函数通常在挂载或渲染之前调用一次。
因此,调用 this.props.loadAuthCookie()
也可能在 componentDidMount
内部工作,但我会接受 Tony 的建议并在 render()
函数中尝试。
【讨论】:
感谢您的建议,但这会触发最大更新深度超出错误。如果有帮助,我已将我的 loadAuthCookie 代码添加到问题中。 听起来this.props.loadAuthCookie()
正在强制渲染(在渲染期间)创建这个无限的渲染循环。需要尝试的几件事: 1. 如果您将this.props.loadAuthCookie();
移动到componentDidMount()
,是否会发生“最大更新深度”错误? 2. 您可能可以在调用this.props.loadAuthCookie()
之前放置一个保护,这样当auth cookie 已经填充时,它会在以后的渲染中跳过该函数。例如,将调用 loadAuthCookie
包装在条件中,这样它只会在 cookie 不存在时触发:if (!this.props.auth.loggedIn) ...
不,如果我将它移动到 componentDidMount,它不会发生,但它表现出与以前相同的行为。添加一个守卫(在渲染中或在 componentDidMount 中)使其工作,但仅如果应用程序不重新渲染。如果我点击指向 privateRoute 的链接,它会呈现,但是,如果我直接访问 url(即导致应用重新呈现),它会不断重定向到 /login
我不熟悉在使用它的组件中实例化高阶组件的模式。您可以尝试将 PrivateRoute 移出 MainComponent 类(最好移到单独的文件中,在 MainComponent 文件中使用 export default PrivateRoute
和 import PrivateRoute from './privateRoute.ts'
之类的东西)...这可能会使控制流和应用程序状态更容易推理。
以上是关于从cookie异步加载身份验证令牌时,React react-router-dom私有路由不起作用的主要内容,如果未能解决你的问题,请参考以下文章
在 React Redux 应用程序中使用 JWT 身份验证令牌的正确方法
从多页应用程序进行身份验证后,如何在初始下载期间将 JWT 令牌加载到 React?
在 Chromecast Receiver 中利用基于 cookie 的身份验证
您是不是更改 cookie 身份验证用户的身份验证令牌?如果有,多久一次?
如果用于身份验证的 JWT 令牌保存在 HTTP-Only cookie 中,您如何从 cookie 中读取它以便我可以将其包含在请求标头中?