How to Implement Authentication and Authorization with Django

Authentication and authorization are essential components of any web application. They allow you to control access to different resources and ensure that only authorized users can perform certain actions. Django, a popular Python web framework, provides built-in support for implementing authentication and authorization.

In this tutorial, we will cover the steps to implement authentication and authorization in a Django application. We will discuss the following topics:

  1. Setting up a Django project
  2. Creating user registration and login views
  3. Implementing user authentication
  4. Adding authorization to your views
  5. Securing static files

1. Setting up a Django project

Before we can implement authentication and authorization, we need to set up a Django project. If you haven’t already, install Django by running the following command:

pip install Django

Once Django is installed, you can create a new project by running:

django-admin startproject myproject

This will create a new directory called myproject with the basic structure of a Django project. Navigate to the project directory:

cd myproject

Next, create a new Django app for our authentication functionality:

python manage.py startapp authentication

Finally, open myproject/settings.py and add 'authentication' to the INSTALLED_APPS list:

INSTALLED_APPS = [
    ...
    'authentication',
    ...
]

2. Creating user registration and login views

To implement user authentication, we first need to create views for user registration and login. Create a new file called views.py inside the authentication directory, and add the following code:

from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import login, logout

def register(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('/')
    else:
        form = UserCreationForm()
    return render(request, 'register.html', {'form': form})

def login_view(request):
    if request.method == 'POST':
        form = AuthenticationForm(request, data=request.POST)
        if form.is_valid():
            user = form.get_user()
            login(request, user)
            return redirect('/')
    else:
        form = AuthenticationForm()
    return render(request, 'login.html', {'form': form})

def logout_view(request):
    logout(request)
    return redirect('/')

These views use Django’s built-in forms for user registration and login. The register view handles the registration form, saves the new user, and redirects to the homepage. The login_view view handles the login form, authenticates the user, and redirects to the homepage. The logout_view view logs out the user and redirects to the homepage.

3. Implementing user authentication

To enable user authentication in our Django project, we need to configure the authentication backend and update the project’s URLs. Open myproject/settings.py and add the following lines at the end of the file:

LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/'

These lines configure the redirect URL after a successful login or logout.

Next, open myproject/urls.py and add the following code:

from django.urls import include, path
from authentication.views import register, login_view, logout_view

urlpatterns = [
    # ...
    path('register/', register, name='register'),
    path('login/', login_view, name='login'),
    path('logout/', logout_view, name='logout'),
    # ...
]

These lines map the registration, login, and logout views to their respective URLs.

Finally, create the HTML templates for the registration and login forms. Inside the authentication directory, create a new directory called templates. Inside the templates directory, create a new file called register.html and add the following code:

{% extends 'base.html' %}

{% block content %}
  <h2>Register</h2>
  <form method="post" action="{% url 'register' %}">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Register</button>
  </form>
{% endblock %}

And create another file called login.html with the following code:

{% extends 'base.html' %}

{% block content %}
  <h2>Login</h2>
  <form method="post" action="{% url 'login' %}">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Login</button>
  </form>
{% endblock %}

These templates extend a base template called base.html and render the registration and login forms.

4. Adding authorization to your views

Now that we have implemented user authentication, let’s add authorization to our views. Authorization allows us to control access to certain views or resources based on the user’s permissions or roles.

First, let’s create a new Django model to represent a resource that we want to restrict access to. Inside the authentication directory, open models.py and add the following code:

from django.db import models
from django.contrib.auth.models import User

class Document(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    owner = models.ForeignKey(User, on_delete=models.CASCADE)

This model represents a document with a title, content, and an owner. The owner field is a foreign key to the built-in User model. It represents the user who owns the document.

Next, run the following command to create the database tables for our new model:

python manage.py migrate

Now let’s update the views to restrict access to the Document model. Open authentication/views.py and replace the code with the following:

from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import login, logout
from django.contrib.auth.decorators import login_required
from authentication.models import Document

@login_required
def create_document(request):
    if request.method == 'POST':
        title = request.POST['title']
        content = request.POST['content']
        Document.objects.create(title=title, content=content, owner=request.user)
        return redirect('/')
    return render(request, 'create_document.html')

@login_required
def view_document(request, document_id):
    document = Document.objects.get(id=document_id)
    if document.owner == request.user:
        return render(request, 'view_document.html', {'document': document})
    else:
        return render(request, 'access_denied.html')

@login_required
def delete_document(request, document_id):
    document = Document.objects.get(id=document_id)
    if document.owner == request.user:
        document.delete()
        return redirect('/')
    else:
        return render(request, 'access_denied.html')

In these views, we use the @login_required decorator to ensure that only authenticated users can access them. The create_document view allows the user to create a new document. The view_document view displays a document if the authenticated user is the owner, otherwise it renders an “Access Denied” page. The delete_document view only allows the owner to delete a document.

To test these views, create the HTML templates for creating and viewing documents. Inside the authentication/templates directory, create a new file called create_document.html with the following code:

{% extends 'base.html' %}

{% block content %}
  <h2>Create Document</h2>
  <form method="post" action="/create/">
    {% csrf_token %}
    <input type="text" name="title" placeholder="Title">
    <textarea name="content" placeholder="Content"></textarea>
    <button type="submit">Create</button>
  </form>
{% endblock %}

And another file called view_document.html with the following code:

{% extends 'base.html' %}

{% block content %}
  <h2>{{ document.title }}</h2>
  <p>{{ document.content }}</p>
  <a href="/delete/{{ document.id }}">Delete</a>
{% endblock %}

We also need to create an access_denied.html template to display when a user tries to access a document they don’t own. Add the following code to a new file called access_denied.html:

{% extends 'base.html' %}

{% block content %}
  <h2>Access Denied</h2>
  <p>You don't have permission to access this document.</p>
{% endblock %}

5. Securing static files

In addition to securing views and resources, it’s important to secure static files such as CSS, JavaScript, and images. Django provides a secure way to serve static files in production using the collectstatic command.

Start by creating a new directory called static at the same level as manage.py. Inside the static directory, create another directory called css. In the css directory, create a new file called styles.css with the following code:

body {
  background-color: #f1f1f1;
  font-family: Arial, sans-serif;
}

h1 {
  color: #333333;
}

p {
  color: #666666;
}

Next, open myproject/settings.py and add the following lines at the end of the file:

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]

These lines configure Django to serve static files from the static directory.

Finally, run the following command to collect the static files into a single directory:

python manage.py collectstatic

This will collect the static files from the static directory and copy them to the staticfiles directory.

To include the CSS file in our templates, update the base.html file inside the templates directory with the following code:

<!DOCTYPE html>
<html>
<head>
  <title>My Project</title>
  <link rel="stylesheet" type="text/css" href="{% static 'css/styles.css' %}">
</head>
<body>
  <h1>My Project</h1>
  {% block content %}
  {% endblock %}
</body>
</html>

The {% static 'css/styles.css' %} code generates the correct URL for the CSS file.

And that’s it! You have successfully implemented authentication and authorization in your Django project. You now have user registration and login functionality, as well as authorization for certain views and resources.

Conclusion

In this tutorial, we have covered the steps to implement authentication and authorization in a Django application. We started by creating user registration and login views using Django’s built-in forms. We then configured the authentication backend and updated the project’s URLs to enable user authentication. Next, we added authorization to our views to control access based on user permissions. Finally, we secured static files by serving them in a production environment.

Authentication and authorization are important security measures that every web application should implement. With Django’s built-in support, you can easily add these features to your application and ensure that only authorized users can access certain resources.

Related Post