在第一章的《Django auth应用模块》我们简单的介绍了 auth 应用,它能够帮助开发者快速构建用户模块的基本功能,包括用户与用户组的实现以及定义用户与用户组权限等,例如,社交平台需要现有用户才可以发布动态话题;管理后台 admin 需要有用户才能登陆等。而且对于不同的用户,Web 站点还可以提供不同的服务,这就是权限的概念。
Django 框架内置的用户认证系统实现了上述功能,即身份的验证和权限的管理,与其他的内置的模块类似,这套系统能够很好的支持扩展和自定义功能,本章我们将一起认识 Django 的用户认证系统。用户认证系统中定义了三个 Model 用来标识用户与用户关系,分别是 User(用户)、AnonymousUser(匿名用户)和 Group(用户组),它们都定义在下面的路径文件中
在《Django Admin数据表可视化》一节,我们使用 createsuperuser 命令创建了超级用户,在视图函数中我们可以通过 HttpRequest 的 user 属性获取当前的登录用户。这里的用户其实就是 Django 框架中内置的 User Model(即auth_user表)因为它被定义在 auth 应用下所以表名是auth_user,可用如下方式引入 User 模型:
在《Django auth应用模块》中我们提到过 auth_user 表,在执行完毕 migrate 后,它的表结构如下所示:
+--------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | password | varchar(128) | NO | | NULL | | | last_login | datetime(6) | YES | | NULL | | | is_superuser | tinyint(1) | NO | | NULL | | | username | varchar(150) | NO | UNI | NULL | | | first_name | varchar(30) | NO | | NULL | | | last_name | varchar(150) | NO | | NULL | | | email | varchar(254) | NO | | NULL | | | is_staff | tinyint(1) | NO | | NULL | | | is_active | tinyint(1) | NO | | NULL | | | date_joined | datetime(6) | NO | | NULL | | +--------------+--------------+------+-----+---------+----------------+ 11 rows in set (0.02 sec)
对于上表前面介绍是我们只是一笔带过,在这里有必讲解一下需要重点理解的属性。如下所示:
除了基础属性之外,User 中还定义了与 Group 和 Permission(权限)之间的关联关系:
class PermissionsMixin(models.Model):
group=models.ManyToManyField(Group,...)
user_permission=models.ManyToManyField(Permission,...)
User 关联表,即 auth_user_groups 和 auth_user_user_permissions,其表分别结构如下图所示:
mysql> desc auth_user_groups; +----------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | user_id | int(11) | NO | MUL | NULL | | | group_id | int(11) | NO | MUL | NULL | | +----------+---------+------+-----+---------+----------------+ 3 rows in set (0.02 sec) mysql> desc auth_user_user_permissions; +---------------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | user_id | int(11) | NO | MUL | NULL | | | permission_id | int(11) | NO | MUL | NULL | | +---------------+---------+------+-----+---------+----------------+ 3 rows in set (0.02 sec)
我们可以使用 User 模型的 create_user 和 create_superuser 分别创建用户或者是超级用户,在创建超级用户的时候需要注意 is_staff 与 is_superuserd 的 bool 值,需要都设置为 Ture 才可以。下面看一下查看其中一个方法即 create_user 的源代码,通过查看,加深对 Django 的学习,如下所示:
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, username, email, password, **extra_fields):
"""
创建并保存具有给定用户名、电子邮件和密码的用户。
"""
if not username:
raise ValueError('The given username must be set')
email = self.normalize_email(email)
#使用户名规范化调用normalize_username
username = self.model.normalize_username(username)
#新建user实例
user = self.model(username=username, email=email, **extra_fields)
#设置密码的方法
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, username, email=None, password=None, **extra_fields):
#普通用户的is_staff和is_superuser都为False
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return self._create_user(username, email, password, **extra_fields)
使用该方法的实例如下所示:
from django.contrib.auth.models import User
user=User.objects.create_user('bookstore','123@163.com','python_django')
同样我们可以 set_password() 方法修改密码,最后记得调用 save() 方法保存即可。
对于 AnonymousUser ,它的常见用法是对视图的请求,对于未登陆的用户,request 的 user 属性即指向了 AnonymousUser 表示匿名用户,我们看一下这个类是如何实现的:
class AnonymousUser:
id = None
pk = None
username = ''
is_staff = False
is_active = False
is_superuser = False
_groups = EmptyManager(Group)
_user_permissions = EmptyManager(Permission)
从源码分析可以看出 AnonymousUser 定义匿名用户的主要属性, 可以看到它的 is_staff 和 is_active 以及 is_superuser 都设置成为了 False,它还定义了一些方法如下所示:
def save(self):
raise NotImplementedError("Django doesn't provide a DB representation for AnonymousUser.")
def delete(self):
raise NotImplementedError("Django doesn't provide a DB representation for AnonymousUser.")
def set_password(self, raw_password):
raise NotImplementedError("Django doesn't provide a DB representation for AnonymousUser.")
def check_password(self, raw_password):
raise NotImplementedError("Django doesn't provide a DB representation for AnonymousUser.")
从上述代码可以看出 AnonymousUser 匿名用户定义的方法都抛出了 NotImplementedError 异常,所以它并没实现任何方法。
上面讲解了用户模型与匿名用户模型,最后一个模型就是用户组 Group,首先我们来理解一下用户组的概念。
组是对用户进行分类的通用方法,以便将权限或其他标签应用到这些用户。用户可以属于任意数量的组。组中的用户自动拥有授予该组的所有权限。例如,如果“网站编辑”组有权限 can_edit_home_page,该组中的任何用户都将拥有该权限。除了权限之外,组还可以方便地对用户进行分类,以便对他们应用一些标签或扩展功能。例如,您可以创建一个“特殊用户”组,并且您可以编写相应的代码对这个特殊用户组,让组内用户做一些特殊的事情——比如让他们访问您站点的成员权限部分,或者给他们发送成员权限的电子邮件消息。
然后我们可以查看一下 Django 实现 Group 编写的源码部分。如下所示:
class Group(models.Model):
name = models.CharField(_('name'), max_length=150, unique=True)
permissions = models.ManyToManyField(
Permission,
verbose_name=_('permissions'),
blank=True,
)
objects = GroupManager()
class Meta:
verbose_name = _('group')
verbose_name_plural = _('groups')
def __str__(self):
return self.name
def natural_key(self):
return (self.name,)
从源码解析来看,Group 用户组之定义了一个字段 name,代表用户组的名称而且必须具有唯一性,其最大字符长度为 150,它还定义与 Permission 模型之间多对多关联关系,那么它们之间就有有一张中间表即 auth_group_permissions,通过数据库查看一下它的表结构,如下所示:
mysql> desc auth_group_permissions; +---------------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | group_id | int(11) | NO | MUL | NULL | | | permission_id | int(11) | NO | MUL | NULL | | +---------------+---------+------+-----+---------+----------------+
下面我们创建一个用户组名称为 reader,然后将 user 加入到该组当中:
In [1]: from django.contrib.auth.models import User,Group
In [2]: group=Group.objects.create(name="reader")
In [3]: user=User.objects.get(username="bookstore")
In [4]: user.groups.add(group)
In [5]: user.groups.all()
Out[5]: <QuerySet [<Group: reader>]>
通过上述的代码就将用户 user 加入到了组 reader 中,我们可以通过用户组权限再给这个组设置相应的权限,查看 auth_user_groups 表可得如下结果:
mysql> select * from auth_user_groups; +----+---------+----------+ | id | user_id | group_id | +----+---------+----------+ | 1 | 2 | 1 | +----+---------+----------+
本节我们详细介绍了 Django 用户认证系统中的用户与用户组,从源码的角度出发对它们之间的关联关系进行了深度的剖析,通过本节的讲解大家对用户与用户组的概念不在感到陌生,在下一节我们将讲解如何进行用户的身份认证。