浅谈 Django内部 用户认证 模块

  我们之前学习了Django 的cookies和session的方法用于用户认证,其实Django框架内部已经内部封装一个用于用户认证的方法!今天有时间研究了下,瞬间感觉Django真是细微之至!

转自:原文出处

auth模块是Django提供的标准权限管理系统,可以提供用户身份认证, 用户组和权限管理。
auth可以和admin模块配合使用, 快速建立网站的管理系统。
在Django框架同名的settings.py配置文件中,可以在INSTALLED_APPS的配置信息中看到'django.contrib.auth'用于使用该APP, auth模块默认启用。

User

  User是auth模块中维护用户信息的关系模式(继承了models.Model), 数据库中该表被命名为auth_user.

  User对象是认证系统的核心。用户对象通常用来代表网站的用户,并支持例如访问控制、注册用户、关联创建者和内容等。在Django认证框架中只有一个用户类,例如超级用户('superusers’)或('staff')用户只不过是相同用户对象设置了不同属性而已。

User表的SQL描述:

CREATE TABLE "auth_user" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, 
"password" varchar(128) NOT NULL, "last_login" datetime NULL, 
"is_superuser" bool NOT NULL, 
"first_name" varchar(30) NOT NULL, 
"last_name" varchar(30) NOT NULL,
"email" varchar(254) NOT NULL, 
"is_staff" bool NOT NULL, 
"is_active" bool NOT NULL,
"date_joined" datetime NOT NULL,
"username" varchar(30) NOT NULL UNIQUE
)

User表内各字段解释

username 用户名,必需字段。30个字符或更少,可以包含 _, @, +, . 和 - 字符。

first_name 可选。 30 characters or fewer.

last_name 可选。 30 characters or fewer.

email 邮箱,可选。 Email address.

password 密码,必需。Django不是以明文存储密码的,而是存储哈希值。

groups 用户组。Many-to-many relationship to Group

user_permissions 用户权限。Many-to-many relationship to Permission

	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")
	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")
		
is_staff  Boolean。决定用户是否可以访问admin管理界面。默认False。

is_active Boolean。 用户是否活跃,默认True。一般不删除用户,而是将用户的is_active设为False。

is_superuser  Boolean。默认False。当设为True时,用户获得全部权限。

	def has_perm(self, perm, obj=None):
		"""
		Returns True if the user has the specified permission. This method
		queries all available auth backends, but returns immediately if any
		backend returns True. Thus, a user who has permission from a single
		auth backend is assumed to have permission in general. If an object is
		provided, permissions for this specific object are checked.
		"""
	 
		# Active superusers have all permissions.
		if self.is_active and self.is_superuser:
			return True
	 
		# Otherwise we need to check the backends.
		return _user_has_perm(self, perm, obj)
last_login 上一次的登录时间,为datetime对象,默认为当时的时间。
	user.last_login = timezone.now()
date_joined  用户创建的时间

User对象的使用方法Methods

is_anonymous() 是否是匿名用户。

is_authenticated()用户是否通过验证,登陆。

get_full_name() 返回first_name plus the last_name, with a space in between.

get_short_name() 返回first_name.

set_password(raw_password) 设置密码。

check_password(raw_password) 验证密码。

get_group_permissions(obj=None) 返回用户组权限的集合。

get_all_permissions(obj=None) 返回用户所有的权限集合。

has_perm(perm, obj=None) 用户是否具有某个权限。perm的格式是 "<app label>.<permission codename>". 

has_perms(perm_list, obj=None) 用户是否具有权限列表中的每个权限。

  以上就是django自带的用户认证系统使用的模型的全部字段和方法,也就是说django在数据库中储存的字段信息就是以上这些。

auth模块提供了很多API管理用户信息, 在必要的时候我们可以APP的models.py文件中导入User表进行用户认证操作, 比如其它表需要与User建立关联时:

from django.contrib.auth.models import User

如果需要扩展的话,有两种方法:
  1、另外再写一个模型,用OneToOne的形式关联到User中

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

class UserInfo(models.Model):
  user = models.OneToOneField(User)
  head_img = models.ImageField()
  # 其它扩展

2、另写一个模型,直接继承User:

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

class UserInfo(User):
  head_img = models.ImageField()
  # 其它扩展

  无论哪种方法都可以,因为那些已经定义好的字段都是储存在User表中的,而新增的字段储存在另外的表中,只是使用OneToOne的时候,查询的入口略麻烦了些,详情参考django的models。

创建用户

  由于User对象的密码不是明文存储的而是存储一个Hash值, 比如迭代使用Md5算法,所以创建User对象时与通常的Model create不同,需用内置的create_user()方法。

user = User.objects.create_user(username, email, password)
user.save()      #建立user对象
在此,需要调用save()方法才可将此新用户保存到数据库中。

  当然也可以在admin界面中添加用户。使用命令创建超级用户!

python manage.py createsuperuser

认证用户 authenticate()

  验证给出的username和password是否是一个有效用户。如果有效,则返回一个User对象,无效则返回None。

  使用authenticate模块,使用时,先导入模块:

from django.contrib.auth import authenticate

  使用关键字参数传递账户和凭据:

user = authenticate(username=username, password=password)  #认证用户的密码是否有效, 若有效则返回代表该用户的user对象, 若无效则返回None。

  需要注意的是:该方法不检查is_active标志位。

修改用户密码

修改密码是User的实例方法, 该方法不验证用户身份:

user.set_password(new_password)

通常该方法需要和authenticate配合使用:

user = auth.authenticate(username=username, password=old_password)
if user is not None:
    user.set_password(new_password)
    user.save()

登录

先导入模块:

from django.contrib.auth import login

login向session中添加SESSION_KEY, 便于对用户进行跟踪:

login(request, user)

login不进行认证,也不检查is_active标志位, 一般和authenticate配合使用:

user = authenticate(username=username, password=password)
if user is not None:
    if user.is_active:
        login(request, user)

在auth/__init__.py中可以看到login的源代码。

退出登录

logout会移除request中的user信息, 并刷新session:

from django.contrib.auth import logout
def logout_view(request):
    logout(request)

权限判断,只允许登录用户访问

  @login_required修饰器修饰的view函数会先通过session key检查是否登录, 已登录用户可以正常的执行操作, 未登录用户将被重定向到login_url指定的位置。若未指定login_url参数, 则重定向到settings.LOGIN_URL。

from django.contrib.auth.decorators import login_required

@login_required(login_url='/accounts/login/')
def my_view(request):
    ...

Group

django.contrib.auth.models.Group定义了用户组的模型, 每个用户组拥有id和name两个字段, 该模型在数据库被映射为auth_group数据表。

User对象中有一个名为groups的多对多字段, 多对多关系由auth_user_groups数据表维护。Group对象可以通过user_set反向查询用户组中的用户。

我们可以通过创建删除Group对象来添加或删除用户组:

# add
group = Group.objects.create(name=group_name)
group.save()
# del
group.delete()

我们可以通过标准的多对多字段操作管理用户与用户组的关系:

#用户加入用户组
user.groups.add(group)
#或者
group.user_set.add(user)

#用户退出用户组
user.groups.remove(group)
#或者
group.user_set.remove(user)

#用户退出所有用户组
user.groups.clear()

#用户组中所有用户退出组
group.user_set.clear()

Permission

Django的auth系统提供了模型级的权限控制, 即可以检查用户是否对某个数据表拥有增(add), 改(change), 删(delete)权限。

auth系统无法提供对象级的权限控制, 即检查用户是否对数据表中某条记录拥有增改删的权限。如果需要对象级权限控制可以使用django-guardian。

假设在博客系统中有一张article数据表管理博文, auth可以检查某个用户是否拥有对所有博文的管理权限, 但无法检查用户对某一篇博文是否拥有管理权限。

检查用户权限

user.has_perm方法用于检查用户是否拥有操作某个模型的权限:

user.has_perm('blog.add_article')
user.has_perm('blog.change_article')
user.has_perm('blog.delete_article')

上述语句检查用户是否拥有blog这个app中article模型的添加权限, 若拥有权限则返回True。

has_perm仅是进行权限检查, 即是用户没有权限它也不会阻止程序员执行相关操作。

@permission_required装饰器可以代替has_perm并在用户没有相应权限时重定向到登录页或者抛出异常。

# permission_required(perm[, login_url=None, raise_exception=False])

@permission_required('blog.add_article')
def post_article(request):
    pass

每个模型默认拥有增(add), 改(change), 删(delete)权限。在django.contrib.auth.models.Permission模型中保存了项目中所有权限。

该模型在数据库中被保存为auth_permission数据表。每条权限拥有id ,name , content_type_id, codename四个字段。

管理用户权限

User和Permission通过多对多字段user.user_permissions关联,在数据库中由auth_user_user_permissions数据表维护。

#添加权限
user.user_permissions.add(permission)

#删除权限: 
user.user_permissions.delete(permission)

#清空权限: 
user.user_permissions.clear()

用户拥有他所在用户组的权限, 使用用户组管理权限是一个更方便的方法。Group中包含多对多字段permissions, 在数据库中由auth_group_permissions数据表维护。

#添加权限: 
group.permissions.add(permission)

#删除权限: 
group.permissions.delete(permission)

#清空权限: 
group.permissions.clear()

自定义权限

在定义Model时可以使用Meta自定义权限:

class Discussion(models.Model):
    ...
    class Meta:
        permissions = (
            ("create_discussion", "Can create a discussion"),
            ("reply_discussion", "Can reply discussion"),
        )

判断用户是否拥有自定义权限:

user.has_perm('blog.create_discussion')

 

posted @ 2017-08-12 10:51  细雨蓝枫  阅读(451)  评论(0编辑  收藏  举报