【问题标题】:Permission checks from components in a React/Redux applicationReact/Redux 应用程序中组件的权限检查
【发布时间】:2016-10-25 05:57:00
【问题描述】:

我正在尝试与构建 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(&lt;MyComponent /&gt;, admin)

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

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

【问题讨论】:

    标签: javascript reactjs ecmascript-6 redux react-redux


    【解决方案1】:

    对于通过开源项目寻求快速解决方案的任何人,您可以尝试使用react-permissible

    • 根据用户管理特定组件的可见性 权限
    • 在不允许用户查看时替换特定组件 它
    • 根据用户管理特定视图的可访问性
      权限
    • 当不允许用户访问时触发回调 组件/路线

    【讨论】:

      【解决方案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>
      

      它基本上允许开发人员在他们的代码中更具声明性,以便于使用和可维护性。

      【讨论】:

      • 将解释库的链接中的相关内容添加到答案正文中。
      • 更好?感谢您的反馈。根据我的个人资料,我是新来的贡献者。 (我对消费并不陌生,因此觉得需要回馈)。希望我能尽快提供帮助。
      【解决方案3】:

      我发现了一篇文章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
      

      这实际上添加了一个网关检查,该检查适用于您的所有容器,并将根据您的角色指导您。此外,如果您以某种方式点击了错误的 url,它将不允许您访问。

      【讨论】:

        【解决方案4】:

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

        • 从 redux 存储数据中决定身份验证/授权 (there are some workarounds)
        • 如果商店更新(但不是 当前路线)

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

        另一种方法是使用高阶组件。

        您可以使用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>);
            }
        }
        

        【讨论】:

        • 所以子方法可以通过refs获得,很高兴知道,谢谢!
        【解决方案5】:

        如果您使用react-router,处理授权的推荐方法是通过Route 组件中的onEnter 属性。

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

        请参阅docs

        这也是你问题的答案:

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

        所以只需将它们设为静态属性/方法(如 Component.onEnter)。

        【讨论】:

        • 我希望能够将组件包装在一个函数中,以便我可以在路由声明之外使用它,特别是对于那些不绑定到路由的组件。
        • 您可以为您的auth 编写一个包装函数,该函数具有onEnter 所需的签名
        • 我希望能够在组件级别指定签名,以免为每个需要身份验证的组件创建两个 JS 文件。
        • 那么在你的组件中添加static onEnter (prevState, nextState, replace)有什么问题?
        • onEnter 不能很好地与 Redux 应用程序协调,原因如下 (github.com/mjrussell/redux-auth-wrapper) ... * 从 redux 存储数据中决定身份验证/授权(有一些解决方法) * 重新检查身份验证/授权如果商店更新(但不是当前路由) * 如果子路由在受保护路由下发生更改,则重新检查身份验证/授权
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-09-24
        • 1970-01-01
        • 2014-01-02
        • 1970-01-01
        • 2021-12-11
        • 2018-11-12
        • 2017-02-06
        相关资源
        最近更新 更多