深入学习Django中的用户认证体系

200 阅读3分钟

Django 自带一个用户验证系统。它负责处理用户账号、组、权限和基于cookie的用户会话。

官方文档:docs.djangoproject.com/zh-hans/4.2…

django.contrib.auth

django.contrib.auth是Django中的认证和授权系统,它提供了一系列的类和方法来处理用户身份验证、权限控制和用户组管理等功能。

  • User模型:Django默认提供的用户模型,用于存储用户的基本信息,包括用户名、密码和电子邮件地址等。
  • 用户组:Django允许您将用户分组,并将权限分配给这些组,以方便管理和授权。
  • 权限控制:Django提供了一些装饰器和方法,例如@login_requireduser.has_perm(),用于控制访问权限和资源保护。
  • 认证视图:Django提供了一些通用视图,例如LoginViewLogoutView,用于处理用户的登录和注销操作。
  • 表单:Django提供了一些表单类,例如AuthenticationFormUserCreationForm,用于处理用户身份验证和注册等操作。

通过使用django.contrib.auth,您可以轻松地为您的Django应用程序添加身份验证和权限控制功能,从而保护您的应用程序和数据。

INSTALLED_APPS = [
    ...
    'django.contrib.auth',  # 包含了验证框架的内核和它的默认模型。
    'django.contrib.contenttypes',  # Django content type system ,允许你创建的模型和权限相关联。
    ....

MIDDLEWARE = [
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',  # 通过请求管理 sessions
    ...
    'django.contrib.auth.middleware.AuthenticationMiddleware',  # 使用会话将用户和请求关联
    ....

User、Group

用户对象是认证系统的核心。它通常代表了与你的站点交互的人员,并用于允许诸如限制访问、注册用户配置文件、将内容与创建者关联等功能。我们可以使用以下方式来加载User数据模型:

from django.contrib.auth.models import User, Group
user = User.objects.create_user("john", "lennon@thebeatles.com", "johnpassword")
user.last_name = "Lennon"
user.save()

User 对象有两个多对多字段:groupsuser_permissions

myuser.groups.set([group_list])
myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group, ...)
myuser.groups.clear()

myuser.user_permissions.set([permission_list])
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()

User源码分析

class User(AbstractUser): # User类继承了AbstractUser类
class AbstractUser(AbstractBaseUser, PermissionsMixin): # AbstractUser类继承了AbstractBaseUser, PermissionsMixin
    username_validator = UnicodeUsernameValidator() # 用户名校验
    username = models.CharField(
        _("username"),
        max_length=150,
        unique=True,
        help_text=_(
            "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only."
        ),
        validators=[username_validator],
        error_messages={
            "unique": _("A user with that username already exists."),
        },
    )
…… # 定义了其他字段

    objects = UserManager() # objects属性是User模型的默认管理器,它使用UserManager()类来管理User对象
  # 下面定义了一些方法
    def clean(self):
        super().clean()
        self.email = self.__class__.objects.normalize_email(self.email)

    def get_full_name(self):
        """
        Return the first_name plus the last_name, with a space in between.
        """
        full_name = "%s %s" % (self.first_name, self.last_name)
        return full_name.strip()


class AbstractBaseUser(models.Model): # User继承了AbstractBaseUser,用于定义密码
    password = models.CharField(_("password"), max_length=128)
    
class PermissionsMixin(models.Model): # User继承了PermissionsMixin,用于定义组和权限相关的内容
    is_superuser = models.BooleanField( # 是否管理员
        _("superuser status"),
        default=False,
        help_text=_(
            "Designates that this user has all permissions without "
            "explicitly assigning them."
        ),
    )
    groups = models.ManyToManyField( # 多对多的关系,可以将用户与多个用户组相关联
        Group,
        verbose_name=_("groups"),
        blank=True,
        help_text=_(
            "The groups this user belongs to. A user will get all permissions "
            "granted to each of their groups."
        ),
        related_name="user_set",
        related_query_name="user",
    )
    # ser_permissions字段是用于将特定权限分配给单个用户
    user_permissions = models.ManyToManyField(
        Permission, # 将用户与特定权限相关联
        verbose_name=_("user permissions"),
        blank=True,
        help_text=_("Specific permissions for this user."),
        related_name="user_set",
        related_query_name="user",
    )
class Group(models.Model):
    name = models.CharField(_("name"), max_length=150, unique=True)
    # permissions字段是用于将特定权限分配给用户组
    permissions = models.ManyToManyField( # 将用户组与特定权限相关联
        Permission,
        verbose_name=_("permissions"),
        blank=True,
    )
    objects = GroupManager()

实战

分析过数据结构后,我们就可以很清晰的获取我们想要的数据,例如:

获取用户的名字和其对应的组

users = User.objects.all()
user_list = []
for user in users:
  username = user.username
  groups = user.groups.all()
  group_list = [group.name for group in groups]
  user_list.append({"username": username, "groups": group_list})

为用户添加删除组

user = User.objects.get(username="john")
group = Group.objects.get(name="admin")
user.groups.add(group)
user.groups.remove(group)

登陆、登出

登陆

from django.contrib.auth import authenticate, login


def my_view(request):
    username = request.POST["username"]
    password = request.POST["password"]
    user = authenticate(request, username=username, password=password)
    if user is not None:
        login(request, user)
        # Redirect to a success page.
        ...
    else:
        # Return an 'invalid login' error message.

登出

from django.contrib.auth import logout


def logout_view(request):
    logout(request)
    # Redirect to a success page.

我们可以使用request.user.is_authenticated来验证用户是否登陆