In the previous article we’ve added signup and login features to the frontend. After login we are redirected to the Dashboard view. However, you can access Dashboard view even if you are not logged in. In this post we will make the AuthenticatedComponent for Dashboard so only logged users will be able to access it. If not logged user would like to access the Dashboard URL then she will be redirected to Login with redirect information in the URL /login?next=/dashboard. We will also add logout feature in the Dashboard.

We will use code from the previous article: React Token Based Authentication to Django REST API Backend (code with tag v4).

Authenticated Component

In the frontend/src/utils directory please add a new file RequireAuth.js:

// frontend/src/utils/RequireAuth.js
import React from "react";
import { connect } from "react-redux";
import { push } from "connected-react-router";
import PropTypes from "prop-types";

export default function requireAuth(Component) {
  class AuthenticatedComponent extends React.Component {
    constructor(props) {
      super(props);
      this.checkAuth();
    }

    componentDidUpdate(prevProps, prevState) {
      this.checkAuth();
    }

    checkAuth() {
      if (!this.props.isAuthenticated) {
        const redirectAfterLogin = this.props.location.pathname;
        this.props.dispatch(push(`/login?next=${redirectAfterLogin}`));
      }
    }

    render() {
      return (
        <div>
          {this.props.isAuthenticated === true ? (
            <Component {...this.props} />
          ) : null}
        </div>
      );
    }
  }
  AuthenticatedComponent.propTypes = {
    isAuthenticated: PropTypes.bool.isRequired,
    location: PropTypes.shape({
      pathname: PropTypes.string.isRequired
    }).isRequired,
    dispatch: PropTypes.func.isRequired
  };

  const mapStateToProps = state => {
    return {
      isAuthenticated: state.auth.isAuthenticated,
      token: state.auth.token
    };
  };

  return connect(mapStateToProps)(AuthenticatedComponent);
}

The requireAuth() function returns the AuthenticatedComponent that can wrap any component. It checks isAuthenticated variable from the auth store. If the user is authenticated then wrapped component is rendered. Otherwise, there is redirect to the Login view with next information in the URL:

// read the current location
const redirectAfterLogin = this.props.location.pathname;
// go to login and pass current location in next parameter
this.props.dispatch(push(`/login?next=${redirectAfterLogin}`));

We check if the user is authenticated in the constructor and after the component update in the componentDidUpdate(). It might be worth checking the diagram showing React component lifecycle.

Please go to the frontend/src/App.js file, and wrap Dashboard component with requireAuth() function:

// frontend/src/App.js
// ...
// add import
import requireAuth from "./utils/RequireAuth";
// ...
// add requireAuth function
<Route path="/dashboard" component={requireAuth(Dashboard)} />
//...

Please clear your localStorage data if you are logged in (in the developer tools in the browser). Then, please open http://localhost:3000/dashboard in your browser. You should be redirected to http://localhost:3000/login?next=/dashboard. Please login, and you should be redirected to the Dashboard view.

Add Navbar and logout in the Dashboard

Let’s improve our Dashboard view:

  • We will add a Navbar at the top of the website. We will add there link to the Home view, information about username, and logout link.
  • On logout click, the user will be redirected to the Home view. All user information from the localStorage will be removed.
// frontend/src/components/dashboard/Dashboard.js

import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";

import { Container, Navbar, Nav } from "react-bootstrap";
import { logout } from "../login/LoginActions";

class Dashboard extends Component {
  onLogout = () => {
    this.props.logout();
  };

  render() {
    const { user } = this.props.auth;
    return (
      <div>
        <Navbar bg="light">
          <Navbar.Brand href="/">Home</Navbar.Brand>
          <Navbar.Toggle />
          <Navbar.Collapse className="justify-content-end">
            <Navbar.Text>
              User: <b>{user.username}</b>
            </Navbar.Text>
            <Nav.Link onClick={this.onLogout}>Logout</Nav.Link>
          </Navbar.Collapse>
        </Navbar>
        <Container>
          <h1>Dashboard</h1>
        </Container>
      </div>
    );
  }
}

Dashboard.propTypes = {
  logout: PropTypes.func.isRequired,
  auth: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  auth: state.auth
});

export default connect(mapStateToProps, {
  logout
})(withRouter(Dashboard));

The logout() function is imported from LoginActions.js file. It is sending POST request to REST API backend. What is more, it clears user and token information in the store and in the localStorage.

You should get the view as in the image below. Please play it with it. For example, you can try to login, then open new tab with http://localhost:3000/dashboard URL.

Dashboard with navbar

Commit changes to the repository

Remember to commit changes to the repository:

# run from the main directory
git add frontend/src/utils/RequireAuth.js
git commit -am "add auth component"
git push

Summary

  • We’ve created the AuthenticatedComponent that checks if user is logged in.
  • If user is logged, then the wrapped component is rendered. Otherwise, there is a redirect to the Login view.
  • We’ve added a navbar in the Dashboard view. There is a Logout link, that sends logout request, clears all user data in the browser, and redirects to the Home view.

What’s next?

In the next article we will add a simple CRUD (Create, Read, Update, Delete) model in the backend and in the frontend.

Next article: CRUD in Django Rest Framework and React.


Let's stay in touch!

Would you like to be notified about new posts? Please fill this form.

Have you found a bug in the code? Please add a GitHub issue.

Do you have problems with running the code or setup and need help? Please add a StackOverflow question with django-react tag.


Boilerplate Tutorial Articles:
1. Starting SaaS with Django and React
2. React Routing and Components for Signup and Login
3. Token Based Authentication with Django Rest Framework and Djoser
4. React Token Based Authentication to Django REST API Backend
5. React Authenticated Component (↩ you are here!)
6. CRUD in Django Rest Framework and React
7. Docker-Compose for Django and React with Nginx reverse-proxy and Let's encrypt certificate
8. Django Rest Framework Email Verification
9. Django Rest Framework Reset Password
More articles coming soon!

Link to the code repository: saasitive/django-react-boilerplate