Django中的用户认证概述
Django带有一个用户认证系统,它负责处理用户账户、组、权限以及用户会话cookie。认证系统包括认证和授权(authentication 和 antuorization
),认证是对一个系统声明的用户进行验证,授权是决定哪个已经认证的用户允许做什么。认证系统包括:
- 用户(Users)
- 权限(Permissions)
- 用户组(Groups)
- 一个可配置的密码散列系统
- 表单和查看工具,用于登录用户或限制内容
- 可插入的后端系统 *
安装
认证在django.contrib.auth
包中作为Django contrib
模块捆绑在一起。 默认情况下,所需的配置已包含在由django-admin startproject
生成的settings.py中,这些配置由INSTALLED_APPS
设置中列出的两个项目组成:
'django.contrib.auth'
:包含认证框架的核心,以及它的默认模型。'django.contrib.contenttypes'
:是Django内容类型系统,它允许权限与创建的模型相关联。
1.User对象
User对象是认证系统的核心, 它代表访问网站的人,可以用于启用限制访问、注册用户配置文件、管理创建者和内容等。在认证框架中,User对象只有一个类:django.contrib.auth.models.User
,超级用户或管理员用户是仅仅具有一些特殊属性的用户,而不是不同的User类。默认主要属性有:
username
:
passoword
:
email
:
first_name
:
last_name
:
创建用户
创建用户最直接的方式是通过create_user()
函数:
>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('john', '[email protected]', 'johnpassword')
# At this point, user is a User object that has already been saved
# to the database. You can continue to change its attributes
# if you want to change other fields.
>>> user.last_name = 'Lennon'
>>> user.save()
create_user(username, email=None, password=None, **extra_fields)
创建超级用户
通过如下命令创建超级用户:
python manage.py createsuperuser
更改密码
Django中不会存储原始文本密码,而是一个hash值,因此不能直接操作User对象的password
属性,Django提供了set_passoword()
方法可以对密码进行修改:
>>> from django.contrib.auth.models import User
>>> u = User.objects.get(username='john')
>>> u.set_password('new password')
>>> u.save()
验证用户
使用authenticate()
方法来验证用户,该方法原型如下:
authenticate(request=None, **credentials)
在验证时,如需要传入一个凭证作为关键字参数,默认使用username
和password
,验证时在每个认证后端列表中检查,如果有效,返回该User对象,否则抛出PermissionDenied
,并返回None
,可以如下形式来验证用户:
from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
# A backend authenticated the credentials
else:
# No backend authenticated the credentials
2.自定义User
在项目开发中,一般不会使用User,而是自定义一个User模型,可以扩充用户字段如:
from django.contrib.auth.models import AbstractUser
class UserProfiles(AbstractUser):
GENDER = (
('male', u'男'),
('female', u'女'),
)
nickname = models.CharField(max_length=20)
birthday = models.DateField(null=True, blank=True)
image = models.ImageField(upload_to='upload/image/%Y/%m')
gender = models.CharField(choices=GENDER)
address = models.CharField(max_length=100)
现在自定义了一个UserProfile模型,当执行python manage.py makemigrations
时,出现错误:
auth.User.groups: (fields.E304) Reverse accessor for 'User.groups' clashes with reverse accessor for 'UserProfiles.g
roups'.
这是因为,在自定义好用户后,还需要配置一下AUTH_USER_MODEL
参数,如果不显式配置该参数,则默认值为auth.User
,配置如下:
AUTH_USER_MODEL = 'users.UserProfiles'
这里需要注意,在配置的时候不是users.models.UserProfiles
,而直接是app.class
的形式
自定义User时出现的一些错误
1.对于ImageField字,需要安装Pillow:
pip install Pillow
2.出现如下异常:
ValueError: Invalid model reference ‘users.models.UserProfiles’. String model references must be of the form ‘app_la
bel.ModelName’.
这是因为将AUTH_USER_MODEL
值配置错误,如 常见的这种错误配置:
AUTH_USER_MODEL=users.models.UserProfiles
,正确的应该为:
AUTH_USER_MODEL=users.UserProfiles
;
3.出现如下异常:
django.db.migrations.exceptions.InconsistentMigrationHistory:
Migration admin.0001_initial is applied before its dep
endency users.0001_initial on database ‘default’.
这是因为原来创建了auth.user
表有依赖,删除表后重新创建一次即可。
3.Web请求的认证
Django使用session和中间件将认证功能系统挂到请求对象上,每次请求时都提供了requset.user
属性,代表当前的用户,如果当前用户没有登录,该属性将被设置为一个AnonymousUser
实例,可以通过is_authenticated
属性进行判断:
if request.user.is_authenticated:
# Do something for authenticated users.
...
else:
# Do something for anonymous users.
...
User.is_authenticated
是一个只读属性,返回值一直为True,与AnonymousUser.is_authenticated
相反,它始终为False
用户登录
在视图中登录用户,使用login()函数进行登录,该函数如下:
login(request, user, backend=None)
,第一个参数为request对象,第二个参数为user对象。login()
函数使用Django的session框架,会将用户的ID保存在session中,登录示例如下:
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.
...
用户登出
如果要退出用户,使用logout()
函数,该函数只带有一个request参数。示例如下:
from django.contrib.auth import logout
def logout_view(request):
logout(request)
# Redirect to a success page.
在注销登录时需要注意:
- 1.如果没有用户登录,使用
logout()
时也不会抛出任何异常; - 2.当使用logout()时,session中的数据将会被清空。
限制登录用户访问
使用is_authenticated
可以通过is_authenticated
属性来限制用户的访问:
from django.conf import settings
from django.shortcuts import redirect
def my_view(request):
if not request.user.is_authenticated:
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
# ...
如果是当前已登录用户,则is_authenticated
返回值永远为True,如果没有登录,则该返回值为False。
使用login_required装饰器
还可以通过@login_required
进行验证,如下所示:
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
...
login_required()
函数原型如下:
login_required(redirect_field_name='next', login_url=None)
,它做了以下工作:
- 如果当前没有用户登录,则会跳转到settings.LOGIN_URL中,并将当前的url绝对路径存储在一个
next
的字符串中; - 如果用户已登录,则正常执行view逻辑。
第一个参数redirect_field_name
可以指定一个字符串来替换next
;
第二个参数login_url
用于指定要跳转的路径,如果指定,则不会再跳转到settings.LOGIN_URL中。