跳转至

用户认证

用户模型

Django 默认提供了一个用户模型 User,如果不符合需求可以自定义,通常继承自 AbstractBaseUser

AbstractBaseUser 提供了用户认证所必需的基本接口和字段,包括密码散列和令牌生成等。继承它允许你保留 Django 用户认证系统的基本功能,同时可以添加额外的字段和方法,以适应你的应用需求。

并且可以与 Django 的其他部分(如中间件、视图和表单)保持兼容,这对于使用诸如用户权限、组和会话等 Django 内置功能至关重要。

当你只想添加额外的字段或改变某些属性时,继承 AbstractUser 可能是更好的选择,它是基于 AbstractBaseUser 的,已经包含了 Django 默认用户模型的所有字段和行为。

from django.contrib.auth.models import AbstractBaseUser

class MyUser(AbstractBaseUser):
    # 添加自定义字段
    pass

设置中添加

AUTH_USER_MODEL = 'myapp.MyUser'

注册

  • forms.py
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User

class MyRegistrationForm(UserCreationForm):
    email = forms.EmailField(required=True)

    class Meta:
        model = User
        fields = ("username", "email", "password1", "password2")
  • views.py
from django.shortcuts import render, redirect
from .forms import MyRegistrationForm

def register(request):
    if request.method == 'POST':
        form = MyRegistrationForm(request.POST)
        if form.is_valid():
            user = form.save(commit=False)
            user.email = form.cleaned_data['email']
            user.save()
            # 这里可以添加用户登录逻辑,或者重定向到登录页面
            return redirect('login')  # 或重定向到其他页面
    else:
        form = MyRegistrationForm()
    return render(request, 'register.html', {'form': form})
  • urls.py
from django.urls import path
from .views import register

urlpatterns = [
    path('register/', register, name='register'),
    # 其他 URL 配置
]
  • templates/register.html
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Register</button>
</form>

登陆

  • forms.py
from django import forms
from django.contrib.auth.forms import AuthenticationForm

class MyLoginForm(AuthenticationForm):
    # 如果需要,可以重写clean方法添加自定义验证逻辑
    def clean(self):
        # 调用父类的清洁方法
        super().clean()

        # 自定义验证逻辑
        # 例如:检查额外字段的值
        # some_extra_field_value = self.cleaned_data.get('some_extra_field')

        # 返回清洁后的数据
        return self.cleaned_data
  • views.py
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login, logout
from .forms import MyLoginForm


# 登入
def login_view(request):
    if request.method == 'POST':
        form = MyLoginForm(request, data=request.POST)
        if form.is_valid():
            username = form.cleaned_data.get('username')
            password = form.cleaned_data.get('password')
            user = authenticate(request, username=username, password=password)
            if user is not None:
                login(request, user)
                return redirect('home')  # 重定向到首页或其他页面
    else:
        form = MyLoginForm()
    return render(request, 'login.html', {'form': form})


# 通过装饰器限制执行视图逻辑之前用户必须已登录,通用视图可以继承内置的混入类来限制
# 如果用户未登陆则默认重定向到登录页面,准确的讲是settings中设置的LOGIN_URL,默认为:/accounts/login/,另外可能还需要定义LOGIN_REDIRECT_URL和LOGOUT_REDIRECT_URL
from django.contrib.auth.decorators import login_required  # 除了限制登录的装饰器外,还有限制权限的装饰器等

@login_required
def my_protected_view(request):
    # 视图逻辑
  • urls.py
from django.urls import path
from .views import login_view

urlpatterns = [
    path('login/', login_view, name='login'),
    # 其他 URL 配置
]
  • templates/login.html
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Login</button>
</form>

登出

  • urls
from django.urls import path
from films import views
from django.contrib.auth.views import LogoutView

urlpatterns = [
    path('index/', views.IndexView.as_view(), name='index'),
    path('login/', views.Login.as_view(), name='login'),
    path('logout/', LogoutView.as_view(), name='logout'),
    path("register/", views.RegisterView.as_view(), name="register")
]

Django v4.1 版本起,LogoutView 需要使用 POST 方式请求

为了安全起见,因为注销操作可能涉及改变用户状态

<div id="navbarNav">
    <ul class="navbar-nav ml-auto">
        {% if user.is_authenticated %}
        <form id="logout-form" method="post" action="{% url 'logout' %}">
            {% csrf_token %}
            <button type="submit">{% translate "Log out" %}</button>
        </form>
        {% else %}
        <li class="nav-item">
            <a class="nav-link" href="{% url 'register' %}">Register</a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'login' %}">Login</a>
        </li>
        {% endif %}
    </ul>
</div>