简介
在一个web系统中,少不了对用户进行认证,这可以说是web系统通用功能,django通过其Auth组件提供了一套完善的用户认证功能。Auth组件在django初始化数据库的时候会建立很多张表,其中与用户认证相关的表名叫:auth_user。
要使用Django自带的认证功能,首先导入auth模块:
from django.contrib import auth
#auth主认证模块
from django.contrib.auth.models import User
#用于orm语法操作auth_user表的数据
Auth组件的应用场景
用户注册
视图层内容:
from django.shortcuts import render,HttpResponse
from django import forms
from django.contrib.auth.models import User
#引入auth组件的user模型,否则无法orm语法操作auth_user表
class RegForm(forms.Form):
name=forms.CharField(max_length=8, label='用户名')
pwd=forms.CharField(max_length=8,label='密码')
email=forms.EmailField()
def register(request):
form_obj=RegForm()
if request.method=="POST":
name=request.POST.get("name")
pwd = request.POST.get("pwd")
email = request.POST.get("email")
User.objects.create_user(username=name,password=pwd,email=email)
#这里必须使用objects的create_user方法,否则密码将会是明文存储在auth_user表中,
#之后的使用将无法通过auth组件进行校验
return HttpResponse('注册成功')
return render(request,'app01/register.html',locals())
模板层register.html部分内容:
<h1>注册用户</h1>
<form action="" method="post" novalidate>
{% csrf_token %}
{% for form_field in form_obj %} <!-- 循环表单对象,获得的是表单的字段对象-->
<p>{{ form_field.label }}:{{ form_field }}</p>
{% endfor %}
<input type="submit" value="注册">
</form>
用户登录认证
视图部分内容:
def login(request):
login_form=RegForm()
if request.method=="POST":
name=request.POST.get('name')
pwd = request.POST.get('pwd')
user_obj=auth.authenticate(request,username=name,password=pwd)
if user_obj:
auth.login(request,user_obj)
##为用户登录状态的校验创建session
return redirect('/home')
return render(request,'app01/login.html',locals())
auth.authenticate方法第一个参数必须是request,对收到的密码先进行加密,再根据收到的用户名和加密后的密码去比对auth_user表。如果auth_user表中比对成功,则返回一个用户对象;如果表中查找不到,则返回None。
auth.login(request,user_obj),类似之前讲过的session操作,会在django_session表中生成一行数据,并在sessionid返回给客户端,之后并可以在任何地方使用request.user活动该用户对象。
模板层login.html
<h1>登陆用户</h1>
<form action="" method="post" novalidate>
{% csrf_token %}
{% for form_field in login_form %}
{% if forloop.last %}
{% else %}
{{ form_field.label }}:{{ form_field }}
{% endif %}
{% endfor %}
<input type="submit" value="登陆">
用户登录状态的检验
视图层增加代码:
from django.contrib.auth.decorators import login_required
......
@login_required()
def home(request):
return HttpResponse('这是家目录')
对于用户登录状态的校验可以使用auth组件的装饰器login_required来完成,只用装饰某个视图函数,就能对其进行登录状态的校验。校验的原理就是比对客户端携带的cookie中和django_session表。如果比对结果为没有登录,则跳转指到登录页面。
登录页面可以分两种:
- 局部配置 @login_required(login_url=’/login/’)
- 全局配置 在settings文件中增添键值对
LOGIN_URL = ‘/login/’
全局的好处在于无需重复写代码 但是跳转的页面却很单一
局部的好处在于不同的视图函数在用户没有登陆的情况下可以跳转到不同的页面
局部配置的优先级高于全局配置
用户注销
视图层:
@login_required
def logout(request):
auth.logout(request)
return redirect('/login/')
auth.logout方法的本质是调用request.session.flush(),清空当前请求对象的session信息。
用户修改密码
视图层:
@login_required()
def set_password(request):
if request.method=="POST":
old_password=request.POST.get('old_password')
new_password=request.POST.get('new_password')
confirm_password=request.POST.get('confirm_password')
if new_password == confirm_password:
is_right=request.user.check_password(old_password)
if is_right:
request.user.set_password(new_password)
request.user.save()
return redirect('login')
return redirect('/set_password')
return render(request,'app01/set_password.html')
模板层:
<h1>修改密码</h1>
<form action="" method="post">
{% csrf_token %}
旧密码:<input type="password" name="old_password">
新密码:<input type="password" name="new_password">
确认新密码:<input type="password" name="confirm_password">
<input type="submit" value="修改">
</form>
Auth组件用户模型的扩展
auth组件默认使用auth_user作为用户模型,其默认自带如下字段:
username:用户名
email: 电子邮件
password:密码
first_name:名
last_name:姓
is_active: 是否为活跃用户。默认是True
is_staff: 是否为员工。默认是False
is_superuser: 是否为管理员。默认是False
date_joined: 加入日期。系统自动生成。
我们利用auth作为web应用的用户的认证系统,当我们想要更多的字段来描述用户时,就需要auth的用户模型进行扩展。
扩展的方法是利用ORM模型的继承,其原理就是类的继承。
进行扩展的前提:
- 在继承之前,django没有执行过数据库迁移命令创建出auth_user表,如果创建了则需要换一个数据库
- 继承的新模型中,不能对AbstractUser模型中原有的字段进行修改,只能增添新字段
- 需要在settings配置文件中告知使用新的模型替代auth_user模型,AUTH_USER_MODEL=‘应用名.表名’
举例为用户添加一个phone字段,在models文件中:
from django.db import models
from django.contrib.auth.models import User,AbstractUser
class UserInfo(AbstractUser):
phone = models.BigIntegerField()
create_time = models.DateTimeField(auto_now_add=True)