2

I'm trying to protect my routes in ReactJS. On each protected routes I want to check if the user saved in localStorage is good.

Below you can see my routes file (app.js) :

class App extends Component {
    render() {
        return (
            <div>
                <Header />
                <Switch>
                    <Route exact path="/" component={Home} />
                    <Route path="/login" component={Login} />
                    <Route path="/signup" component={SignUp} />
                    <Route path="/contact" component={Contact} />
                    <ProtectedRoute exac path="/user" component={Profile} />
                    <ProtectedRoute path="/user/person" component={SignUpPerson} />
                    <Route component={NotFound} />
                </Switch>
                <Footer />
            </div>
        );
    }
}

My protectedRoute file :

const ProtectedRoute = ({ component: Component, ...rest }) => (
    <Route {...rest} render={props => (
        AuthService.isRightUser() ? (
            <Component {...props} />
        ) : (
            <Redirect to={{
                pathname: '/login',
                state: { from: props.location }
            }}/>
        )
    )} />
);

export default ProtectedRoute;

And my function isRightUser. This function send a status(401) when the data aren't valid for the user logged :

async isRightUser() {
    var result = true;
    //get token user saved in localStorage
    const userAuth = this.get();

    if (userAuth) {
        await axios.get('/api/users/user', {
            headers: { Authorization: userAuth }
        }).catch(err => {
            if (!err.response.data.auth) {
                //Clear localStorage
                //this.clear();
            }

            result = false;
        });
    }

    return result;
}

This code is not working and I don't know really why. Maybe I need to call my function AuthService.isRightUser() with a await before the call and put my function async ?

How can I update my code to check my user before accessing a protected page ?

Cracs
  • 425
  • 1
  • 8
  • 29

2 Answers2

6

I had the same issue and resolved it by making my protected route a stateful class.

Inside switch I used

<PrivateRoute 
    path="/path"
    component={Discover}
    exact={true}
/>

And my PrivateRoute class is as following

class PrivateRoute extends React.Component {

    constructor(props, context) {
        super(props, context);

        this.state = {
            isLoading: true,
            isLoggedIn: false
        };

        // Your axios call here

        // For success, update state like
        this.setState(() => ({ isLoading: false, isLoggedIn: true }));

        // For fail, update state like
        this.setState(() => ({ isLoading: false, isLoggedIn: false }));

    }

    render() {

        return this.state.isLoading ? null :
            this.state.isLoggedIn ?
            <Route path={this.props.path} component={this.props.component} exact={this.props.exact}/> :
            <Redirect to={{ pathname: '/login', state: { from: this.props.location } }} />

    }

}

export default PrivateRoute;
Burak Gavas
  • 1,304
  • 1
  • 9
  • 11
  • Perfect ! it's better with a class and react states. – Cracs Apr 10 '19 at 12:39
  • I have a axios call for login inside my login component that is returning me token and login response. How can I use that call from the login component in PrivateRoute component? – program_bumble_bee Nov 02 '19 at 07:15
  • 1
    Hi @bubble-cord. Your login component should be a public route because everyone should be able to get into login page without authentication. After doing an axios call in your public login component, you can just redirect user to the main page with `this.props.history.push('/main')` – Burak Gavas Nov 02 '19 at 22:48
0

When you annotate a function with async like you did in AuthService.isRightUser() it returns a Promise and you are not treating the response of the method accordingly.

As you suggested, you could call the method AuthService.isRightUser() with await and annotate the function you are passing to the render property with async.

Or you could treat the response of AuthService.isRightUser() with a .then() and .catch() instead of the ternary operator

f-CJ
  • 4,235
  • 2
  • 30
  • 28