Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript React HOC:更改帐户类型时重定向错误_Javascript_Reactjs_Firebase_Redux_Firebase Authentication - Fatal编程技术网

Javascript React HOC:更改帐户类型时重定向错误

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,

我使用Access创建了一个高阶组件
,以检查用户是否具有进入某些受保护路由的权限(登录和帐户角色)。我使用的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;