React router v4 - Authorized routes with HOC

前端 未结 2 2038
清歌不尽
清歌不尽 2020-12-20 02:27

I have a problem to prevent unauthorized users from accessing authorized-only routes/components - such as logged in users dashboard

I have the following code:

<
相关标签:
2条回答
  • 2020-12-20 02:32

    Since you are using React Router 4, the answer by Matthew Barbara, while absolutely correct, is unnecessarily complicated. With RR4 you can simply use the Redirect component to handle your redirects. See https://reacttraining.com/react-router/web/api/Redirect for more info.

    import React, { Component } from "react";
    import { connect } from "react-redux";
    import { Redirect } from "react-router-dom";
    
    export default function requireAuth (WrappedComponent) {
    
      class Authentication extends Component {
    
        render () {
    
          if (!this.props.authenticated) {
            return <Redirect to="/"/>
          }
    
          return <WrappedComponent { ...this.props }/>
        }
      }
    
      function mapStateToProps (state) {
        return { authenticated: state.authenticated }
      }
    
      return connect(mapStateToProps)(Authentication);
    }
    
    0 讨论(0)
  • 2020-12-20 02:34

    Warning: The following answer uses React's old context API. If you are using V16.3+, the following answer does not apply to you

    Ok, so, according to your logic, unauthorized users are prohibited to access the User component. Simple and fair. No problems with that.

    But my concern is that are you checking if the user is logged in inside a component which unauthenticated users should not get into. This is incorrect in my opinion because:

    1. It's an extra journey for our program - adds an extra bit of unnecessary inefficiency. There is a possibility that from the router we go to User component and the latter sends us back to the former. Ping pong.

    2. The User component looks dirty. Having irrelevant logic. Yes irrelevant. Because authentication check should not be done in User component. User component should contain user related stuff.

    What do you think if instead of getting inside the User component to check users authentication, we check this in the router? User component, as it name describe, is dedicated for users and the logic to check authentication should be taken out from there.

    Ok, Thats cool. But how?

    We can create a Higher-Order Component (HOC) which as an argument will take any component was pass to it. Then, we add authentication logic inside the HOC and finally, depending on the logic we use we can either redirect to the homepage or allow the request to the given component.

    In order for the HOC to be able to do the above it needs access to:

    1. State. We need to know whether the user is logged in and the state is where we store such data.
    2. Router. We may need to redirect users.

    Lets name the HOC required_auth. Here is the code of it:

    import React, { Component } from 'react';
    import { connect } from 'react-redux';
    
    export default function(ComposedComponent) {
        class Authentication extends Component {
            static contextTypes = {
                router: React.PropTypes.object
            }
    
            componentWillMount() {
                if (!this.props.authenticated) {
                    this.context.router.history.push('/');
                }
            }
    
            componentWillUpdate(nextProps) {
                if (!nextProps.authenticated) {
                    this.context.router.history.push('/');
                }
            }
    
            render() {
                return <ComposedComponent {...this.props} />
            }
        }
    
        function mapStateToProps(state) {
            return { authenticated: state.auth.authed };
        }
    
        return connect(mapStateToProps)(Authentication);
    }
    

    As you can see, there is no black magic happening here. What might be confusing is

    static contextTypes = {
        router: React.PropTypes.object
    }
    

    context is similar to props but it allows us to skip levels in our component hierarchy

    Because this.context is very easy to access and abuse, React forces us to define the context in this way.

    Do not use context unless you really know what you are doing. The use case for context is not that common. Read more on what the consequences could be here

    To conclude on our HOC, it simply takes a component as an argument and it either redirect to the homepage or returns the component that we will pass to it.

    Now to use it, in route file we import the HOC

     import RequiredAuth from './components/auth/required_auth';
    

    and any routes which we want to protect from non-authoirzed users we simply route it like this:

    <Route path="/user" component={RequiredAuth(User)}/>
    

    The line above will either direct to homepage or returns the component which we are passing, User

    References: https://facebook.github.io/react/docs/higher-order-components.html https://facebook.github.io/react/docs/context.html

    0 讨论(0)
提交回复
热议问题