In-depth analysis of django user authentication system

Building a robust web application is inseparable from secure user authentication and fine-grained permission control. Django has a built-in powerful and flexible user authentication system, which can cover almost all common needs, from basic login registration to complex object-level permissions. This tutorial will take you to systematically master Django user authentication, from core concepts to high-level practices, and build a reliable identity management system step by step.

1. Basics of authentication system

Many developers easily confuse two concepts: Authentication and Authorization. Simply put, authentication answers "Who are you?" and authorization answers "What can you do?". Django's authentication system is built around these two cores.

Django's authentication system mainly consists of the following parts:

  • User model: stores user information, the default isdjango.contrib.auth.models.User
  • Authentication backend: Logic for verifying user identity, pluggable and replaceable.
  • Permissions and Groups: Control user access to specific resources.
  • Session Framework: Maintain user login status.

A typical certification process is as follows:

  1. The user submits a username and password.
  2. django callauthenticate()Method that tries all configured authentication backends one by one.
  3. After successful verification by the backend, a user object is returned.
  4. Subsequent callslogin()Write the user ID to the session.

The authorization process goes throughhas_perm()has_module_perms()etc. in methods or templates{% if perms.app_label.codename %}Tag implementation that checks whether the user has permission to perform a specific action.

2. Custom user model

In actual projects, logging in with a mobile phone number or email is far more common than using a username. Django recommends customizing the user model from the beginning to avoid the huge cost of later migration.

2.1 Extend AbstractUser

If you only need to add a few fields to the default user model (such as avatar, mobile phone number), inheritAbstractUseris the best choice.

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

class User(AbstractUser):
    phone = models.CharField(max_length=11, unique=True, verbose_name='手机号')
    avatar = models.ImageField(upload_to='avatars/', blank=True, verbose_name='头像')

    class Meta:
        db_table = 'users'

then insettings.pyStatement in:

AUTH_USER_MODEL = 'myapp.User'

2.2 Fully customized model

If you want to use email as a unique identifier, remove it completely.usernamefields, you need to inheritAbstractBaseUserandPermissionsMixin

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models

class UserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError('必须提供邮箱地址')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        return self.create_user(email, password, **extra_fields)

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    name = models.CharField(max_length=150)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['name']

USERNAME_FIELDSpecifies the fields used during authentication,REQUIRED_FIELDSis an additional field that is required when creating a superuser.

3. Authentication backend configuration

Django's authentication backend is pluggable, and you can support email login, LDAP login or mobile phone verification code login at the same time.

3.1 Custom authentication backend

A simple email login backend:

from django.contrib.auth.backends import BaseBackend
from django.contrib.auth import get_user_model

User = get_user_model()

class EmailBackend(BaseBackend):
    def authenticate(self, request, email=None, password=None):
        try:
            user = User.objects.get(email=email)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

then insettings.pyRegister in:

AUTHENTICATION_BACKENDS = [
    'myapp.backends.EmailBackend',
    'django.contrib.auth.backends.ModelBackend',   # 保留默认后端
]

3.2 Integrate OAuth2 or JWT

When developing APIs, django REST Framework is often useddjangorestframework-simplejwtImplement JWT authentication.

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
}

Front end passes/api/token/Obtain the access and refresh token, and then carry them in the request headerAuthorization: Bearer <token>That’s it.

4. Permissions and group management

django's permissions start withapp_label.codenameFormat storage, such asblog.add_postblog.change_post. By default every model hasaddchangedeleteviewFour permissions.

  • User Level Permissions:user.user_permissions.add(permission)
  • Group-level permissions: Grant permissions to a group, and then add users to the group to achieve batch permission management.
  • Custom permissions: in modelMetaStatement inpermissions
class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()

    class Meta:
        permissions = [
            ('can_publish', '可以发布文章'),
            ('can_archive', '可以归档文章'),
        ]

When checking permissions you can useuser.has_perm('blog.can_publish'). If you need object-level permissions (for example, you can only modify articles you create), you need to use a third-party library such asdjango-guardian

5. Safety Practices

The security of authentication systems cannot be taken lightly. Here are a few key points:

  • Password Policy: Django uses the PBKDF2 algorithm to hash passwords by default and supports password complexity verification. Can useAUTH_PASSWORD_VALIDATORSConfigure rules such as length, universality, mixed numbers and letters, etc.
  • Session Security: SettingsSESSION_COOKIE_AGEControl expiration time,SESSION_EXPIRE_AT_BROWSER_CLOSE = TrueIt will become invalid when the browser is closed.CSRF_COOKIE_HTTPONLYImprove security.
  • Account Lock: Passeddjango-axesPlug-ins such as this can easily limit the number of failed logins and temporarily lock accounts, effectively resisting brute force cracking.
  • HTTPS mandatory: must be turned on in production environmentSECURE_SSL_REDIRECTand set it correctlySECURE_HSTS_SECONDS

6. Implementation of common functions

In daily development, there are several certification-related requirements that almost every project will encounter.

6.1 Password reset

Django has a built-in password reset view, just configure the email backend:

# urls.py
from django.contrib.auth import views as auth_views

urlpatterns = [
    path('password-reset/', auth_views.PasswordResetView.as_view(), name='password_reset'),
    path('password-reset/done/', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
    path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
    path('reset/done/', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
]

6.2 Registration and activation

Send an activation email to verify the validity of the user's email address. The key is to generate a unique token and set the expiration time.

from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_encode

uid = urlsafe_base64_encode(str(user.pk).encode())
token = default_token_generator.make_token(user)
link = f'https://example.com/activate/{uid}/{token}'
# 通过邮件发送 link,用户点击后调用 token 校验函数

6.3 "Remember Me"

Implementing the "remember me" feature simply extends the session lifetime on login:

if request.POST.get('remember_me'):
    request.session.set_expiry(1209600)  # 两周
else:
    request.session.set_expiry(0)        # 关闭浏览器即失效

Summarize

Django's user authentication system is the cornerstone of building secure applications. From custom user models to fine-grained permission controls to security policies to prevent attacks, every step deserves to be taken seriously. After mastering these contents, you can not only quickly implement regular user management needs, but also customize secure and flexible authentication and authorization solutions based on project characteristics.


📚 Recommended reading:


*This article was carefully written by the Daoman PythonAI team. You are welcome to forward and share it. Please indicate the source when reprinting. *