首页 文章

来自React / Redux应用程序中的组件的权限检查

提问于
浏览
4

我正在尝试与团队一起构建一个React应用程序,并试图找出创建“更高阶”React组件(一个包装另一个组件)的最佳方法,以便与Redux数据存储一起执行身份验证 .

到目前为止,我的方法是创建一个模块,该模块由一个函数组成,该函数根据是否有经过身份验证的用户返回一个新的React组件 .

export default function auth(Component) {

    class Authenticated extends React.Component {

        // conditional logic

        render(){
            const isAuth = this.props.isAuthenticated;

            return (
                <div>
                    {isAuth ? <Component {...this.props} /> : null}
                </div>
            )
        }
    }

    ...

    return connect(mapStateToProps)(Authenticated);

}

这使我的团队中的其他人可以轻松指定组件是否需要特定权限 .

render() {
    return auth(<MyComponent />);
}

如果您正在执行基于角色的检查,这种方法是有道理的,因为您可能只有几个角色 . 在这种情况下,你可以调用 auth(<MyComponent />, admin) .

对于基于权限的检查,传递参数变得难以处理 . 但是,在构建组件时(以及在团队环境中可管理),可以在组件级别指定权限 . 设置静态方法/属性似乎是一个不错的解决方案,但据我所知,es6类导出为函数,它们不会显示可调用方法 .

有没有办法访问导出的React组件的属性/方法,以便可以从包含组件访问它们?

5 回答

  • 1

    对于任何想要使用开源项目快速修复它的人,您可以尝试使用react-permissible .

    • 根据用户权限管理特定组件的可见性

    • 在不允许用户查看时替换特定组件

    • 根据用户管理特定视图的可访问性
      权限
      当不允许用户访问组件/路由时,

    • 触发回调

  • 1

    onEnter 很棒,在某些情况下很有用 . 但是,以下是一些常见的身份验证和授权问题onEnter无法解决:

    • 确定redux商店数据的身份验证/授权(there are some workarounds

    • 如果商店更新(但不是当前路线),请重新检查身份验证/授权

    • 如果子路由在受保护路由下发生更改,请重新检查身份验证/授权

    An alternative approach is to use Higher Order Components.

    You can use Redux-auth-wrapper提供更高阶的组件,以便于读取和应用组件的身份验证和授权约束 .


    • 要获取子方法,您可以使用: refs, callback and callback from refs

    • 要获得儿童道具,您可以使用: this.refs.child.props.some or compInstance.props.some

    方法和道具的示例:

    class Parent extends Component {
        constructor(props){
            super(props);
            this.checkChildMethod=this.checkChildMethod.bind(this);
            this.checkChildMethod2=this.checkChildMethod2.bind(this);
            this.checkChildMethod3=this.checkChildMethod3.bind(this);
        }
        checkChildMethod(){
            this.refs.child.someMethod();
            console.log(this.refs.child.props.test);
        }
        checkChildMethod2(){
            this._child2.someMethod();
            console.log(this._child2.props.test);
        }
        checkChildMethod3(){
            this._child3.someMethod();
            console.log(this._child3.props.test);
        }
        render(){
            return (
                <div>
                    Parent
                    <Child ref="child" test={"prop of child"}/>
                    <ChildTwo ref={c=>this._child2=c} test={"prop of child2"}/>
                    <ChildThree returnComp={c=>this._child3=c} test={"prop of child3"}/>
                    <input type="button" value="Check method of child" onClick={this.checkChildMethod}/>
                    <input type="button" value="Check method of childTwo" onClick={this.checkChildMethod2}/>
                    <input type="button" value="Check method of childThree" onClick={this.checkChildMethod3}/>
                </div>
            );
        }
    }
    
    class Child extends Component {
        someMethod(){
            console.log('someMethod Child');
        }
        render(){
            return (<div>Child</div>);
        }
    }
    class ChildTwo extends Component {
        someMethod(){
            console.log('someMethod from ChildTwo');
        }
        render(){
            return (<div>Child</div>);
        }
    }
    class ChildThree extends Component {
        componentDidMount(){
            this.props.returnComp(this);
        }
        someMethod(){
            console.log('someMethod from ChildThree');
        }
        render(){
            return (<div>Child</div>);
        }
    }
    
  • 2

    这似乎是一个非常有趣的可能性我点击这个问题谷歌搜索相同的问题,这是一个新的库,所以我认为链接它不会伤害,以防其他任何人可以得到它的帮助 . 我还没有决定自己是否会自己走这条路,因为我进入Google-palooza只需15分钟 . 它叫做CASL .

    Link to the Article Explaining the Library

    Link to the Library

    每个请求来自库的示例代码:

    if (ability.can('delete', post)) {
      <button onClick={this.deletePost.bind(this}>Delete</button>
    }
    

    取代像:

    if (user.role === ADMIN || user.auth && post.author === user.id) {
      <button onClick={this.deletePost.bind(this}>Delete</button>
    }
    

    在文章中,作者通过自定义组件进一步获得:

    <Can run="delete" on={this.props.todo}>
      <button onClick={this.deleteTodo.bind(this}>Delete</button>
    </Can>
    

    它基本上允许开发人员在代码中更具说明性,以便于使用和维护 .

  • 1

    如果使用 react-router ,则建议的处理授权的方法是通过 Route 组件中的 onEnter 属性 .

    <Route path="/" component={Component} onEnter={Component.onEnter} />
    

    docs .

    它也是你问题的答案:

    有没有办法访问导出的React组件的属性/方法,以便可以从包含组件访问它们?

    所以只需要使它们成为静态属性/方法(如Component.onEnter) .

  • 1

    我找到了一篇文章here,我在这里写的要点 . 您可以像这样为您的组件添加道具

    <Route path="/" component={App}>
    
    //BOD routes
    <Route authorisedUsers={['KR']} path="/home" component={HomeContainer} />
    
    //HR routes
    <Route authorisedUsers={['HR']} path="/hrhome" component={HRDashboardContainer} />
    
    //common routes    
    <Route authorisedUsers={['KR', 'HR']} path="/notes" component={NotesContainer} />
    

    然后在组件中添加以下代码,在path ='/'上呈现

    Role based routing react redux
    componentDidUpdate() {
      const { 
          children,  //Component to be rendered (HomeContainer if route = '/home')
          pathname: {location},  //location.pathname gives us the current url user is trying to hit. (with react router)
          profileId, //profileId required by profile page common to all user journeys.
          role } = this.props; 
      this.reRoute(role, this.props.children, location.pathname, ProfileId)
    }
    
    decideRoute(role, ProfileId) { //decide routes based on role
      if(role==='HR')
        return 'hrhome';
      else if(role==='KR')
        return 'home';
      else if(role==='USER'&&ProfileId)
        return 'profile/'+ProfileId;
      else
      return '/error';
    }
    
    isAuthorised(authorisedUsers, role) {
      return _.includes(authorisedUsers, role)
    }
    
    reRoute(role, children, path, ProfileId) {
      if(role===null && path!=='/') // user hit a different path without being authenticated first
      {
        hashHistory.replace('/');  //this is where we implemented login
        return;
      }
      let route = this.decideRoute(role, ProfileId)  //if role has already been fetched from the backend, use it to decide the landing page for each role.
      if(children)  // if we already are on one of the user journey screens ...
      {
        const authorisedUsers = children.props.route.authorisedUsers 
        if(!this.isAuthorised(authorisedUsers,role)) //... and the user is not allowed to view this page...
        hashHistory.replace(`/${route}/`);  //... redirect him to the home page corresponding to his role.
      }
      else
      hashHistory.replace(`/${route}/`);  // if the user has just logged in(still on / page or login page), and we know his role, redirect him to his home page.
    }//if none of these holds true, user is allowed to go ahead and view the page
    

    这实质上增加了一个网关检查,可以在所有容器上运行,并根据您的角色指导您 . 此外,如果你以某种方式打错了网址,它将不允许你访问 .

相关问题