Javascript React HOC:更改帐户类型时重定向错误
我使用Access创建了一个高阶组件Javascript React HOC:更改帐户类型时重定向错误,javascript,reactjs,firebase,redux,firebase-authentication,Javascript,Reactjs,Firebase,Redux,Firebase Authentication,我使用Access创建了一个高阶组件,以检查用户是否具有进入某些受保护路由的权限(登录和帐户角色)。我使用的hoc是这样的: const authCondition = authUser => !!authUser; <Route path="/a" component={WithAccess(authCondition, "admin")(Admin)} /> <Route path="/u" component={WithAccess(authCondition,
,以检查用户是否具有进入某些受保护路由的权限(登录和帐户角色)。我使用的hoc是这样的:
const authCondition = authUser => !!authUser;
<Route path="/a" component={WithAccess(authCondition, "admin")(Admin)} />
<Route path="/u" component={WithAccess(authCondition, "user")(User)} />
const authCondition=authUser=>!!authUser;
管理员和用户是两个具有路由的功能组件
WithAccess包含onAuthStateChanged侦听器。在侦听器中,我正在检查用户的角色(创建用户时,我正在设置自定义声明“角色”)。如果这与传递的prop“role”匹配,isLoading将设置为false,组件将呈现。否则,用户将被重定向回登录页面
const WithAccess = (condition, role) => Component => {
class withAccess extends React.Component {
state = {
isLoading: true
};
componentDidMount() {
Auth.onAuthStateChanged(async user => {
if (user) {
const idTokenResult = await user.getIdTokenResult(true);
if (condition(user) && idTokenResult.claims.role === role)
this.setState({ isLoading: false });
else this.props.history.push(`/login`);
}
});
}
render() {
return !this.state.isLoading ? (
<Component />
) : (
<PageLoader label="Checking user..." />
);
}
}
return withRouter(withAccess);
};
export default WithAccess;
constwithaccess=(条件、角色)=>Component=>{
使用Access扩展React.Component初始化{
状态={
孤岛加载:正确
};
componentDidMount(){
Auth.onAuthStateChanged(异步用户=>{
如果(用户){
const idTokenResult=await user.getIdTokenResult(true);
if(条件(用户)&&idTokenResult.claims.role===角色)
this.setState({isLoading:false});
否则这个.props.history.push(`/login`);
}
});
}
render(){
返回!这个.state.isLoading(
) : (
);
}
}
通过路由器返回(通过访问);
};
使用Access导出默认值;
这是有效的。但是,当我从管理员帐户切换到用户帐户或从visa帐户切换到用户帐户时,WithAccess将传递上一个角色
为了澄清问题,我在一个代码沙盒中重新制作了登录/注册部分:
复制的最佳方式:
转到登录页面并注册新用户
重定向到用户仪表板时注销
以管理员身份登录并发送电子邮件:admin@example.com密码:123456
“登录”将在导航中更改为“Dashboard”,但您将停留在登录页面上(事实上,您会被重定向到/a/Dashboard,但WithAccess会立即将您重定向回)
我正在试图理解为什么WithAccess在从帐户类型切换时会传递上一个角色,但还没有弄清楚。您的应用程序中存在内存泄漏!很难抓住这些:)
在具有HOC访问权限的情况下,您必须取消对firebase onAuth回调的侦听
如果在某处添加侦听器,请始终记住清理组件
componentDidMount() {
//Retain a reference to the unlistener callback
this.fireBaseAuthUnlistener = Auth.onAuthStateChanged(async user => {
if (user) {
const idTokenResult = await user.getIdTokenResult(true);
console.log("ID Token claims: ", idTokenResult.claims);
console.log("ROLE : ", role);
if (condition(user) && idTokenResult.claims.role === role) {
this.setState({ isLoading: false });
console.log(user);
} else {
this.props.history.push(`/login`);
}
}
});
}
componentWillUnmount() {
//Unlisten when unmounting!
this.fireBaseAuthUnlistener && this.fireBaseAuthUnlistener();
this.fireBaseAuthUnlistener = undefined;
}
我认为您应该大大简化您的路由结构,首先将经过身份验证的路由包装在ProtectedRoutes
HOC中。此路由仅允许经过身份验证(登录)的用户查看它。然后添加另一个RequireAdmin
HOC以检查角色是否为admin
。如果没有,它将重定向到NotFound
页面
经过身份验证的用户可以访问/u/仪表板
,但当他们单击管理仪表板
链接时,会显示一个未找到
页面。但是,管理员可以访问这两个
要测试:
- 单击
Login
- 以
testuser123@example.com
使用密码123456
- 重定向时,尝试访问管理仪表板
- 重定向到
NotFound
页面
- 单击
返回
- 单击仪表板
单击Logout
再次单击登录
admin@example.com
使用密码123456
用户仪表板
和管理员仪表板
(两者都可以工作)容器/受保护的路线
import isEmpty from "lodash/isEmpty";
import React, { Component, Fragment } from "react";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import Navigation from "../../components/Website/Navigation";
class ProtectedRoutes extends Component {
componentDidMount = () => {
if (isEmpty(this.props.user) || !this.props.user.email) {
this.props.history.push("/notfound");
}
};
componentDidUpdate = prevProps => {
if (this.props.user !== prevProps.user) {
this.props.history.push("/notfound");
}
};
render = () =>
this.props.user.email ? (
<Fragment>
<Navigation />
{this.props.children}
</Fragment>
) : null;
}
export default connect(state => ({ user: state.user }))(
withRouter(ProtectedRoutes)
);
路线(主)
从“React”导入React;
从“react router dom”导入{Route,Switch};
从“./容器/ProtectedRoutes”导入ProtectedRoutes;
从“./components/Admin”导入管理员;
从“./页面/网站/主页”导入主页;
从“./页面/网站/NotFound”导入NotFound;
从“./containers/LoginForm”导入LoginForm;
从“./containers/RegisterForm”导入RegisterForm;
从“./组件/用户”导入用户;
常数路由=()=>(
);
导出默认路径;
组件/用户(受用户保护的路由)
import React,{Fragment}来自“React”;
从“react router dom”导入{Route,Switch};
从“../../pages/User/Dashboard”导入仪表板;
从“../../pages/Website/NotFound”导入NotFound;
常量用户=({match})=>(
);
导出默认用户;
组件/Admin(受管理员保护的路由)
import React,{Fragment}来自“React”;
从“react router dom”导入{Route,Switch};
从“../../containers/RequireAdmin”导入RequireAdmin;
从“../../pages/Admin/Dashboard”导入仪表板;
从“../../pages/Website/NotFound”导入NotFound;
常量Admin=({match})=>(
);
导出默认管理员;
我试图复制,但它按预期正常工作!我没有被从仪表板重定向。这是一个好消息和坏消息,哈哈。也许是我的浏览器里有什么特别的东西。我能重现错误。我猜就是这样。添加了unlistener,并尝试了几次使用不同的帐户类型进行注册和登录。到目前为止没有错误@托尔:是的,很可能是!如果回答了您的问题,请不要忘记标记为已回答:)
import isEmpty from "lodash/isEmpty";
import { Component } from "react";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
class RequireAdmin extends Component {
componentDidMount = () => {
if (isEmpty(this.props.user) || this.props.user.role !== "admin") {
this.props.history.push("/notfound");
}
};
componentDidUpdate = prevProps => {
if (this.props.user !== prevProps.user) {
this.props.history.push("/notfound");
}
};
render = () =>
isEmpty(this.props.user) || this.props.user.role === "admin"
? this.props.children
: null;
}
export default connect(state => ({ user: state.user }))(
withRouter(RequireAdmin)
);
import React from "react";
import { Route, Switch } from "react-router-dom";
import ProtectedRoutes from "../containers/ProtectedRoutes";
import Admin from "../components/Admin";
import Home from "../pages/Website/Home";
import NotFound from "../pages/Website/NotFound";
import LoginForm from "../containers/LoginForm";
import RegisterForm from "../containers/RegisterForm";
import User from "../components/User";
const Routes = () => (
<div>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/login" component={LoginForm} />
<Route exact path="/register" component={RegisterForm} />
<Route exact path="/notfound" component={NotFound} />
<ProtectedRoutes>
<Route path="/u" component={User} />
<Route path="/a" component={Admin} />
</ProtectedRoutes>
</Switch>
</div>
);
export default Routes;
import React, { Fragment } from "react";
import { Route, Switch } from "react-router-dom";
import Dashboard from "../../pages/User/Dashboard";
import NotFound from "../../pages/Website/NotFound";
const User = ({ match }) => (
<Fragment>
<Switch>
<Route exact path={`${match.url}/dashboard`} component={Dashboard} />
<Route path={`${match.url}`} component={NotFound} />
</Switch>
</Fragment>
);
export default User;
import React, { Fragment } from "react";
import { Route, Switch } from "react-router-dom";
import RequireAdmin from "../../containers/RequireAdmin";
import Dashboard from "../../pages/Admin/Dashboard";
import NotFound from "../../pages/Website/NotFound";
const Admin = ({ match }) => (
<RequireAdmin>
<Switch>
<Route exact path={`${match.url}/dashboard`} component={Dashboard} />
<Route path={`${match.url}`} component={NotFound} />
</Switch>
</RequireAdmin>
);
export default Admin;