DEV Community

DoriDoro
DoriDoro

Posted on

Django built-in authentication system

Introduction:

In this article I will explain to you how to create a simple Django project with the basic login and logout authentication process. Django has built-in authentication systems and built-in views that you can use to quickly and easily create a user authentication using your own templates.

Create the Django project:

Create a new project in your IDE or Terminal and go to the folder you have created. Create a virtual environment.

Now install the dependencies inside your virtual environment:

pip install django python-decouple ipyhton
Enter fullscreen mode Exit fullscreen mode

You can chain multiple dependencies together. You install Django for your project. python-decouple is for the .env file where you put all your secret environment variables, like the SECRET_KEY or all email configurations, etc. And ipython is a nice tool for the shell.

After you have successfully installed your dependencies, store them in a file in the root directory with:

pip freeze > requirements.txt
Enter fullscreen mode Exit fullscreen mode

pip freeze lists all dependencies in terminal
> requirements.txt this will save all installed dependencies in a the file called requirements.txt or create the file.

Now build your Django project inside the virtual environment using:

django-admin startproject authentication .
Enter fullscreen mode Exit fullscreen mode

The . after the name of your project is to create the Django project directory inside the root directory.

After you have created your first application inside the Django project:

python manage.py startapp accounts
Enter fullscreen mode Exit fullscreen mode

The application has to be added into to the INSTALLED_APPS in the settings.py file inside the authentication project directory.

# authentication/settings.py

# Application definition
INSTALLED_APPS = [
    "accounts",
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
]
Enter fullscreen mode Exit fullscreen mode

If you want to create your own custom authentication templates, you need to make sure that your created application accounts is placed before the "django.contrib.admin" application.


Ensure security of your project:

To ensure the security of your project, you should store the SECRET_KEY, DEBUG, ALLOWED_HOSTS, etc. in a locally stored .env file.

Enter the above command in your terminal to create a secure SECRET_KEY:

python manage.py shell -c 'from django.core.management import utils; print(utils.get_random_secret_key())'
Enter fullscreen mode Exit fullscreen mode

Create an .env file in the root directory and add:

# general project variables:
SECRET_KEY="r^=cy=8w8$^p)!gd6#%*c)s-u4h!ua9r6!i317qt^6l47)94t^"
DEBUG=True
ALLOWED_HOSTS=localhost,127.0.0.1
Enter fullscreen mode Exit fullscreen mode

To be able to start your development server, you need to have access to the project variables such as the SECRET_KEY. You need to make sure that your settings.py file has access to the environment variables stored in the .env file.

The first step is already done by installing python-decouple. Now update the settings.py file:

# authentication/settings.py

from decouple import config


# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = config("SECRET_KEY")

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = config("DEBUG")

ALLOWED_HOSTS = config("ALLOWED_HOSTS", default="").split(",")
Enter fullscreen mode Exit fullscreen mode

ALLOWED_HOSTS should be a list. We have stored the value as a comma separated string in the .env file. Within the settings.py file, we split the comma-separated strings at the , and create a list from them.

The next file you need to create is the .gitignore file, to avoid sending your environment variables to GitHub or GitLab.

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# Django stuff:
*.log
*.pot
*.pyc

# virtual environment
.venv

# IDE
.idea

# Local configuration
.env
Enter fullscreen mode Exit fullscreen mode

This .gitignore file is just an example, yours may look different depending on your IDE.


Creating a User model:

It is good practice to use the AbstractUser to create your own user model:

# accounts/models.py

from django.contrib.auth.models import AbstractUser


class User(AbstractUser):
    pass
Enter fullscreen mode Exit fullscreen mode

If necessary, you can add additional attributes within the User class.

The next step is to add the User model to the Admin Panel. This way you can easily create User instances from the admin panel. You can also create User instances in the Python shell.

# accounts/models.py

from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin

UserModel = get_user_model()

admin.site.register(UserModel, UserAdmin)
Enter fullscreen mode Exit fullscreen mode

In the settings.py file, we need to set the User we created to tell the project that we want to use our custom User model.

# authentication/settings.py

# set the User
AUTH_USER_MODEL = "accounts.User"
Enter fullscreen mode Exit fullscreen mode

The next commands create the migration file inside the accounts application and create the database tables inside the SQLite database.

python manage.py makemigrations
python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

Now, it is time to create an admin user in terminal:

python manage.py createsuperuser

Username: Admin
Email address: admin@mail.com
Password: 
Password (again): 
Superuser created successfully.
Enter fullscreen mode Exit fullscreen mode

Remember or save these authentication details for future use.


Setting the authentication URLs and creating custom authentication templates:

The new application was already added to the project when we added the accounts name to the INSTALLED_APPS list in settings.py, but we need to integrate all future url patterns from the accounts application into the project URL file:

# authentication/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("accounts/", include("accounts.urls", namespace="accounts")),
]
Enter fullscreen mode Exit fullscreen mode

We will include all url patterns of the accounts application, which will be under the accounts namespace.

Inside the accounts application, create a new file called urls.py and add the following:

# accounts/urls.py

from django.urls import path, include


app_name = "accounts"

urlpatterns = [
    path("", include("django.contrib.auth.urls")),
]
Enter fullscreen mode Exit fullscreen mode

The app_name should be the same as the namespace attribute inside the path() function in the authentication urls.py file.

If you start the development server with:

python manage.py runserver
Enter fullscreen mode Exit fullscreen mode

and navigate to the URL: http://127.0.0.1:8000/accounts/ you will have access to the following URL patterns:

admin/
accounts/ login/ [name='login']
accounts/ logout/ [name='logout']
accounts/ password_change/ [name='password_change']
accounts/ password_change/done/ [name='password_change_done']
accounts/ password_reset/ [name='password_reset']
accounts/ password_reset/done/ [name='password_reset_done']
accounts/ reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/ reset/done/ [name='password_reset_complete']
Enter fullscreen mode Exit fullscreen mode

Let's create a test user and navigate to http://127.0.0.1:8000/admin/. Enter the username in my example: Admin and the password you set with the python manage.py createsuperuser command.

Under the heading ACCOUNTS you can add a new user. You enter the username, twice the password and save it. Then you have to enter additional information such as first and last name and email address and save again.


Login and Logout view:

The first template we will create is the base.html template in the accounts application. First create a directory inside the accounts application called: templates and inside the templates directory create a file called base.html:

<!-- accounts/templates/base.html -->

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{% block title %}{% endblock %}</title>
</head>
<body>
  <div>
    <span class="logo">Authentication</span>
      {% if request.user.is_authenticated %}
        <ul class="menu">
          <li {% if section == "dashboard" %}class="selected"{% endif %}>
            <a href="{% url 'accounts:dashboard' %}">My dashboard</a>
          </li>
        </ul>
      {% endif %}
    <span class="user">
      {% if request.user.is_authenticated %}
        Hello {{ request.user.first_name|default:request.user.username }},
        <form action="{% url 'accounts:logout' %}" method="post">
          <button type="submit">Logout</button>
          {% csrf_token %}
        </form>
      {% else %}
        <a href="{% url 'accounts:login' %}">Log-in</a>
      {% endif %}
    </span>
  </div>

  <div id="content">
    {% block content %}
    {% endblock %}
  </div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

The URL syntax in my case always has the application name accounts before the URL name, otherwise the URL name will not be found. If the authentication URL is in a namespace, the application name must be added.

We will create three additional templates, a login template, a logged_out template and a template after the user has successfully logged in, a dashboard.

<!-- accounts/templates/registration/login.html -->

{% extends "base.html" %}

{% block title %}Log-in{% endblock %}

{% block content %}
  <h1>Log-in</h1>
  {% if form.errors %}
    <p>
      Your username and password didn't match.
      Please try again.
    </p>
  {% else %}
    <p>
      Please, use the following form to log-in.

    </p>
  {% endif %}
  <div class="login-form">
    <form method="post">
      {{ form.as_p }}
      {% csrf_token %}
      <input type="hidden" name="next" value="{{ next }}" />
      <p><input type="submit" value="Log-in"></p>
    </form>

  </div>
{% endblock %}
Enter fullscreen mode Exit fullscreen mode
<!-- accounts/templates/registration/logged_out.html -->

{% extends "base.html" %}

{% block title %}Logged out{% endblock %}

{% block content %}
  <h1>Logged out</h1>
  <p>
    You have been successfully logged out.
    You can <a href="{% url 'accounts:login' %}">log-in again</a>.
  </p>
{% endblock %}
Enter fullscreen mode Exit fullscreen mode

Make sure you use the template name: logged_out otherwise this template will be ignored.

<!-- accounts/templates/dashboard.html -->

{% extends "base.html" %}

{% block title %}Dashboard{% endblock %}

{% block content %}
  <h1>Dashboard</h1>
  <p>Welcome to your dashboard.</p>
{% endblock %}
Enter fullscreen mode Exit fullscreen mode

It is not done yet. We need to create the view and an URL for the dashboard and set some variables in the settings.py file.

# accounts/views.py

from django.contrib.auth.decorators import login_required
from django.shortcuts import render


@login_required
def dashboard(request):
    return render(request, "dashboard.html", {"section": "dashboard"})
Enter fullscreen mode Exit fullscreen mode

Only an authenticated user has access to this view, we ensure this with the login_required decorator.

# accounts/urls.py

from django.urls import path, include

from accounts.views import dashboard

app_name = "accounts"

urlpatterns = [
    path("", include("django.contrib.auth.urls")),
    path("", dashboard, name="dashboard"),
]
Enter fullscreen mode Exit fullscreen mode

In settings.py file we have to set some variable to ensure the redirection after the login to our dashboard URL:

# authentication/settings.py

LOGIN_REDIRECT_URL = "accounts:dashboard"
LOGIN_URL = "login"
LOGOUT_URL = "logout"
Enter fullscreen mode Exit fullscreen mode

The LOGIN_REDIRECT_URL leads the way to the dashboard URL pattern inside the accounts application.


Top comments (0)