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 theHome
view, information about username, and logout link. - On logout click, the user will be redirected to the
Home
view. All user information from thelocalStorage
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.
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 aLogout
link, that sends logout request, clears all user data in the browser, and redirects to theHome
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.
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