(10) Django - Auth认证系统

Django除了有强大的Admin管理系统,还提供了完善的用户管理系统。整个用户管理系统可分为三大部分:用户信息、用户权限和用户组,在数据库中分别对应数据表auth_user、auth_permission和auth_group。

内置USER用户管理

本节将使用内置的用户管理系统实现用户的注册、登录、修改密码和注销功能。以mysite为例,在项目中创建新的App,命名为user,并在项目的settings.py和urls.py中配置App的信息。

E:\mysite>python manage.py startapp user

#settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'index',
    'user',
]

#urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('index.urls')),
    path('user/', include('user.urls'))
]

完成user的基本配置后,在App中分别添加urls.py和user.html文件。添加后的目录结构如图:


(10) Django - Auth认证系统_第1张图片
image.png

还要在settings.py中启用该模板文件。

'DIRS': [os.path.join(BASE_DIR, 'user/templates'),
               ],

App的urls.py设定

在user下的urls.py中设定4个不同的URL地址,分别代表用户登录、注册、修改密码和用户注销:

#user的urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('login.html', views.loginView, name='login'),
    path('register.html', views.registerView, name='register'),
    path('setpassword.html', views.setpasswordView, name='setpassword'),
    path('logout.html', views.logoutView, name='logout'),
]

上述URL地址分别对应试图函数loginView、registerView、setpasswordView和logoutView。在编写视图函数之前,首先了解一下user.html模板的代码结构:




    
    {{ title }}
    


{{ headers }}

{% if tips %}
{{ tips }}
{% endif %}
{% csrf_token %}
用户名:
密 码:
{% if new_password %}
新密码:
{% endif %}

一个模板分别用于实现用户登录、注册和修改密码,该模板是由两个文本输入框和一个按钮所组成的表单,在该表单下分别设置不同链接,分别指向另外两个URL地址。


image.png

用户登录

接下来,在views.py中实现用户登录功能,视图函数loginView的代码如下:

#user 的 views.py
from django.shortcuts import render, redirect
from django.contrib.auth.models import User
from django.contrib.auth import login, logout, authenticate

def loginView(request):
    #设置标题和两外两个URL链接
    title = '登录'
    headers = '用户登录'
    unit_2 = '/user/register.html'
    unit_2_name = '立即注册'
    unit_1 = '/user/setpassword.html'
    unit_1_name = '修改密码'

    if request.method == 'POST':
        #用户提交登录,获取登录的用户名和密码
        username = request.POST.get('username', '')
        password = request.POST.get('password', '')
        #首先查找User数据表中有没有该用户,没有提示注册
        if User.objects.filter(username=username):
            #如果有该用户,则检查用户名和密码是否正确,错误提示重新输入
            user = authenticate(username=username, password=password)
            if user:
                if user.is_active:##判断用户是否被激活,是则由内置函数login完成登录,跳转到主页
                    login(request, user)
                return redirect('/')
            else:
                tips = '账号密码错误,请重新输入'
        else:
            tips = '用户不存在,请注册'
    return render(request, 'user.html', locals())

以上代码就实现了用户的登录,在整个登录过程中,我们并没有对模型User进行定义,而函数中使用的模型User来自于Django的内置模型,在数据库中对应的数据表为auth_user。该表有以下字段:

字段 说明
id int类型,数据表主键
password varchar类型,用户密码
last_lgoin datetime类型,最近一次登录时间
is_superuser tinyint类型,是否为超级用户
username varchar类型,用户账号
first_name varchar类型,用户的名字
last_name varchar类型,用户的姓氏
email 电子邮件
is_staff 判断用户是否可以可以登录Admin系统
is_active tinyint类型,判断该用户的状态是否被激活
date_joined datetime类型,账号的创建时间

登陆成功后,页面会自动跳转到index的首页,这里将首页的模板稍做修改,添加以下代码:

#index.html
退出登录
用户名:{{ username }}

然后在index的views.py的视图函数index中传递变量username给模板。

#index 下的 views.py
def index(request):
    username = request.user.username
    #以下代码省略
    #...

这样我们登陆以后就可以看到登陆的用户名。
image.png

用户注册

接下来,完成用户注册功能,在user的views.py中编写视图函数registerView,代码如下:

#user的views.py
def registerView(request):
    #设置标题和两外两个URL链接
    title = '注册'
    headers = '用户注册'
    unit_2 = 'login.html'
    unit_2_name = '立即登录'
    unit_1 = 'setpassword.html'
    unit_1_name = '修改密码'

    if request.method == 'POST':
        #获取用户注册的用户名和密码
        username = request.POST.get('username', '')
        password = request.POST.get('password', '')
        #首先查找User数据表中有没有该用户,有则提示用户已存在
        if User.objects.filter(username=username):
            tips = '用户已存在'
        else:
            #创建新用户
            user = User.objects.create_user(username=username, password=password)
            user.save()
            tips = '注册成功,请登录'
    return render(request, 'user.html', locals())

用户注册和用户登录的流程大致相同,这里需要注意一个问题:
用户登录或者注册的url链接是 '/user/register.html',user前面的 ’/‘ 符号一定不能缺。

修改密码

最后在views.py中编写函数setpasswordView,实现修改密码的功能。

#user 的view.py 
def setpasswordView(request):
    #设置标题和两外两个URL链接
    title = '修改密码'
    headers = '密码修改'
    unit_2 = '/user/login.html'
    unit_2_name = '立即登录'
    unit_1 = '/user/register.html'
    unit_1_name = '立即注册'
    new_password = True#控制模板中新密码的文本框是否出现
    if request.method == 'POST':
        username = request.POST.get('username', '')
        old_password = request.POST.get('password', '')
        new_password = request.POST.get('new_password', '')
        if User.objects.filter(username=username):#如果查询到用户表中有该用户,则进行下一步,否则提示用户不存在
            user = authenticate(username=username, password=old_password)#验证用户和密码是否一致
            if user:
                user.set_password(new_password)#通过验证则通过set_password内置函数设置新密码
                user.save()
                tips = '密码修改成功'
            else:
                tips = '用户名和原密码不一致,请重新输入'
        else:
            tips = '用户不存在'
    return render(request, 'user.html', locals())

密码修改界面比注册和登录界面多出一个文本输入框,该输入框由模板变量new_password控制显示。
image.png

上面的密码修改是通过内置函数set_password实现的,而函数set_password是在内置函数make_password的基础上进行封装而来的。内置函数make_password主要是用来实现对用户密码的加密功能,并且该函数可以脱离Auth认证系统单独使用,比如对某些特殊数据进行加密处理等。上述例子中,使用函数make_password实现修改密码的代码部分如下:

from django.contrib.auth.hashers import make_password
#密码加密处理并保存到数据库
dj_pw = make_password(new_password, None, 'pbkdf2_sha256')#加密处理
user.password = dj_pw
user.save()

除了内置函数make_password,还有内置函数check_password,该函数是对加密前的密码与加密后的密码进行验证匹配。判断两者是否为同一密码。在django的shell模式下使用该函数:

>>> from django.contrib.auth.hashers import make_password,check_password
>>> pw = '123456'
>>> dj_pw = make_password(pw, None, 'pbkdf2_sha256')
>>> dj_pw
'pbkdf2_sha256$120000$0ATplZvxaaVN$OIH6gdfMpaYheNtci5iigfod/YIIy4jdkI4UTp60WJM='
>>> check_password(pw, dj_pw)
True

用户注销

用户注销是用户管理系统较为简单的功能,调用内置函数Logout即可实现。代码如下:

#user 的 views.py
def logoutView(request):
    logout(request)#退出登录
    return redirect('/user/login.html')#跳转到登录页面

实现发送邮件找回密码

上面的密码修改是在用户知道密码的情况下实现的,而在日常应用中,还有一种是用户忘记密码的情况下实现密码修改,也叫密码找回。密码找回首先需要对用户账号进行验证,确认该账号是当前用户所拥有的,验证成功后才能给用户重置密码。本节使用Django内置的邮件功能实现邮箱验证,从而实现密码找回功能。
在实现邮件发送功能之前,需要对邮箱进行相关设置,开启POP3/SMTP服务。以网易163邮箱为例,开通POP3服务时会让你输入一个授权码,这个授权码在后面的开发中需要使用。


image.png

image.png

接下来需要在settings.py中添加邮箱的相关配置

#mysite 的 settings.py
#邮箱配置信息
#设置django与邮件服务器的连接方式为SSL
EMAIL_USE_SSL = True
#邮件服务器
EMAIL_HOST = 'smtp.163.com'
#邮件服务器端口,若使用SMTP服务器,端口应为465或587
EMAIL_PORT = 465
#发送邮件的账号
EMAIL_HOST_USER = '[email protected]'
#SMTP服务密码,客户端的授权密码
EMAIL_HOST_PASSWORD = 'fe*********'
#设置默认发送邮件的账号
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER

完成邮箱相关配置后,先到user的urls.py中设置密码找回的URL地址信息,添加以下路径

#user 的 urls.py
path('findpassword.html', views.findpasswordView, name='findpassword'),

添加好URL地址信息后,我们到视图模块中编写视图函数findpasswordView,代码如下:

#user 的 views.py
def findpasswordView(request):
    button = '获取验证码'
    new_password = False
    if request.method == 'POST':
        username = request.POST.get('username','')
        verificationCode = request.POST.get('verificationCode', '')
        password = request.POST.get('password','')
        #验证用户是否存在
        user = User.objects.filter(username=username)
        #用户不存在
        if not user:
            tips = '用户 ' + username + ' 不存在'
        else:
            #用户存在,则判断验证码是否发送
            #如果session中没有验证码信息,则发送验证码并将验证码写入session
            if not request.session.get('verificationCode', ''):
                button = '重置密码'
                tips = '验证码已发送'
                new_password = True#展示新密码文本输入框
                verificationCode = str(random.randint(1000,9999))#生成随机4位数验证码
                request.session['verificationCode'] = verificationCode#将验证码写入session
                user[0].email_user('找回密码', verificationCode)#通过内置函数email_user向用户发送验证码邮件
            #匹配输入的验证码是否正确
            elif verificationCode == request.session.get('verificationCode'):
                #密码加密处理并保存到数据库
                dj_pw = make_password(password, None, 'pbkdf2_sha256')
                user[0].password = dj_pw
                user[0].save()
                del request.session['verificationCode']#删除session中的验证码信息
                tips = '密码已重置'
            else:
                tips = '验证码错误,请重新获取'
                new_password = False
                del request.session['verificationCode']
    return render(request, 'user1.html', locals())

这里用一个新的模板user1.html,与上面的user.html稍有不同。




    
    找回密码
    


密码找回

{% if tips %}
{{ tips }}
{% endif %}
{% csrf_token %}
用户名:
验证码:
{% if new_password %}
新密码:
{% endif %}

输入http://127.0.0.1:8000/user/findpassword.html进入密码找回界面

(10) Django - Auth认证系统_第2张图片
image.png

如果不输入用户名或者输入不存在的用户名则会提示用户不存在。
(10) Django - Auth认证系统_第3张图片
image.png

我们输入用户名user来尝试以下,
image.png

可以看到,网页显示验证码已发送,但是在这之前,需要在数据表中插入用户user的邮箱信息,否则邮件是无法发送出去的。
image.png

打开邮箱可以看到验证码已经发送成功,下面就是输入验证码更改密码。
(10) Django - Auth认证系统_第4张图片
image.png

输入完以后点击重置密码,可以看到密码已重置
image.png

Django除了内置函数email_user实现邮件发送之外,还另外提供多种邮件发送方法,我们在shell模式下讲解:

使用 send_mail 实现邮件发送
>>> from django.core.mail import send_mail
>>> from django.conf import settings
#获取settings.py的配置信息
>>> from_email = settings.DEFAULT_FROM_EMAIL
#发送邮件,接收邮件以列表表示,说明可设置多个接收对象
>>> send_mail('邮件头', '邮件主题', from_email, ['[email protected]'])
1
使用send_mass_mail实现多封邮件同时发送
>>> from django.core.mail import send_mass_mail
>>> from django.conf import settings
>>> from_email = settings.DEFAULT_FROM_EMAIL
>>> message1 = ('邮件头1','邮件主题1', from_email, ['[email protected]'])
>>> message2 = ('邮件头2','邮件主题2', from_email, ['[email protected]'])
#多封邮件信息以元组形式封装发送
>>> send_mass_mail((message1,message2), fail_silently=False)
2
image.png
使用EmailMultiAlternatives 实现邮件发送
>>> from django.core.mail import EmailMultiAlternatives
>>> from django.conf import settings
>>> from_email = settings.DEFAULT_FROM_EMAIL
>>> content = '

这是一封很重要的邮件.

' >>> msg = EmailMultiAlternatives('邮件头', content, from_email, ['[email protected]']) #将正文设置为HTML格式 >>> msg.content_subtype = 'html' #可选,对正文内容进行补充和添加 >>> msg.attach_alternative('是的很重要...', 'text/html') #可选,添加附件 >>> msg.attach_file('E://test.txt') #发送 >>> msg.send() 1
(10) Django - Auth认证系统_第5张图片
image.png

扩展User模型

在开发过程中,模型User的字段可能满足不了复杂的开发需求。现在大多数网站的用户信息都有用户的手机号码、QQ号码和微信号等一系列个人信息。为了满足各种需求,Django还提供了4种模型扩展方法。一般情况下,建议使用AbstractUser扩展模型User,因为该方式对原有模型User影响较少而且无须额外创建数据表。
下面以mysite项目为例讲解如何使用AbstractUser扩展模型User。
首先在MySQL中找到项目所使用的数据库,并清除该数据库中全部的数据表,在user的models.py文件中定义模型MyUser,代码如下:

#user 的 models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class MyUser(AbstractUser):
    qq = models.CharField('QQ号码', max_length=16)
    weChat = models.CharField('微信账号', max_length=100)
    mobile = models.CharField('手机号码', max_length=11)
    # 设置返回值
    def __str__(self):
        return self.username

模型MyUser继承自AbstractUser类,AbstractUser类已有内置模型User的字段属性,因此模型MyUser具有模型User的全部属性。在执行数据迁移(创建数据表)之前,必须要在项目的settings.py中配置相关信息。

#settings.py
AUTH_USER_MODEL = 'user.MyUser'

配置信息是将内置模型User替换成user定义的模型MyUser,若没有设置配置信息,在创建数据表的时候,会分别创建数据表auth_user 和 user_myuser。
在项目命令行下执行数据迁移:

python manage.py makemigrations
python manage.py migrate
完成数据迁移后,打开数据库查看数据表信息,可以发现内置模型User的数据表auth_user改为数据表user_myuser,并且数据表user_myuser的字段除了具有内置模型User的字段,还额外增加了自定义的字段,如图所示:

image.png

接着使用 python manage.py createsuperuser创建超级用户并登录Admin后台管理系统。
(10) Django - Auth认证系统_第6张图片
image.png

我们会发现认证与授权没有用户信息表,这是因为模型MyUser是在user的models.py中定义的。若将模型MyUser展示在后台系统,则要在user的admin.py中定义相关的数据对象:

#admin.py
from django.contrib import admin
from .models import MyUser
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import gettext_lazy as gl

@admin.register(MyUser)
class MyUserAdmin(UserAdmin):
    list_display = ['username', 'email', 'mobile', 'qq', 'weChat']
    #修改用户时,在个人信息里添加 'mobile 、'qq'、'weChat'的信息录入
    #将源码的UserAdmin.fieldsets转换成列表格式
    fieldsets = list(UserAdmin.fieldsets)
    #重写UserAdmin的fieldsets,添加'mobile'、'qq'、'weChat'的信息录入
    fieldsets[1] = (gl('Personal info'), {'fields':('first_name','last_name','email','mobile','qq','weChat')})
#__init__.py
#设置App(user)的中文名
from django.apps import AppConfig
import os
# 修改app在admin后台显示名称
# default_app_config的值来自apps.py的类名
default_app_config = 'user.IndexConfig'

# 获取当前app的命名
def get_current_app_name(_file):
    return os.path.split(os.path.dirname(_file))[-1]

# 重写类IndexConfig
class IndexConfig(AppConfig):
    name = get_current_app_name(__file__)
    verbose_name = '用户管理'

重启mysite项目并进入Admin后台,可以在界面看到模型MyUser生成的用户信息表。

(10) Django - Auth认证系统_第7张图片
image.png

进入用户信息表,并修改某个用户信息时,发现用户信息的修改界面出现用户的手机号码、QQ号码和微信号码的文本输入框,这是由MyUserAdmin类中重写属性fieldsets实现的。
image.png

上述admin.py定义的MyUserAdmin继承自UserAdmin,UserAdmin是内置模型User的Admin数据对象,因此,在定义MyUserAdmin时,直接继承UserAdmin,并通过重写某些属性,可以快速开发扩展模型MyUser的Admin后台数据对象。
除了继承UserAdmin的Admin数据对象之外,还可以在 表单中继承内置模型User所定义的表单类。内置的表单类forms.py说明如下:

表单类 表单字段 说明
UserCreationForm username,password1,password2 创建新的用户信息
UserChangeForm password, 模型User全部字段 修改已有的用户信息
AuthenticationForm username,password 用户登录时所触发的验证功能
PasswordResetForm email 将重置密码通过发送邮件方式实现密码找回
SetPasswordForm password1,password2 修改或新增用户密码,设置密码时,无须对旧密码进行验证
PasswordChangeForm old_password,newpassword1,new_password2 继承SetPasswordForm,修改密码前需要对旧密码进行验证
AdminPasswordChangeForm password1,password2 用于Admin后台修改用户密码

上述内置的表单累都涉及模型User的字段,说明这些表单是在内置模型User的基础上实现的。因此,我们为扩展模型MyUser定义相关的表单累可以继承上述的表单类。以UserCreationForm为例,使用表单类UserCreationForm实现用户注册功能。在user中创建form.py文件:

#user 的 form.py
from django.contrib.auth.forms import UserCreationForm
from .models import MyUser

class MyUserCreationForm(UserCreationForm):
    class Meta(UserCreationForm.Meta):
        model = MyUser
        # 在注册界面添加邮箱、手机号码、微信号码和QQ号码
        fields = UserCreationForm.Meta.fields + ('email', 'mobile', 'weChat', 'qq')

然后在模板user.html和视图函数registerView中编写以下代码:

#模板user.html



    
    用户注册
    


MyDjango Auth

{% if tips %}
{{ tips }}
{% endif %}
{% csrf_token %}
用户名:{{ user.username }}
邮 箱:{{ user.email }}
手机号:{{ user.mobile }}
Q Q 号:{{ user.qq }}
微信号:{{ user.weChat }}
密 码:{{ user.password1 }}
密码确认:{{ user.password2 }}
#user 的 views.py
from django.shortcuts import render
from .form import MyUserCreationForm

# 使用表单实现用户注册
def registerView(request):
    if request.method == 'POST':
        user = MyUserCreationForm(request.POST)
        if user.is_valid():
            user.save()
            tips = '注册成功'
            user = MyUserCreationForm()
    else:
        user = MyUserCreationForm()
    return render(request, 'user.html',locals())

然后在浏览器上访问http://127.0.0.1:8000/user/register.html,就实现了用户注册的功能。

image.png

用户权限

用户权限主要是对不同的用户设置不同的功能使用权限,而每个功能主要以模型来划分。数据库中的数据表auth_permission的每条数据信息就代表项目中某个模型的某个权限:


image.png

设置用户权限实质上是对数据表user_myuser和auth_permission之间的数据设置多对多关系。


(10) Django - Auth认证系统_第8张图片
项目的数据表

从整个项目的数据表可以看到,用户、用户权限和用户组分别对应数据表user_myuser、auth_permission和auth_group.无论是设置用户权限、设置用户所属用户组还是设置用户组的权限,其实质都是对两个数据表之间的数据建立多对多的数据关系:

  • 数据表user_myuser_user_permissions:管理数据表user_myuser和auth_permission之间的多对多关系,实现用户权限设置
  • 数据表user_myuser_groups:管理数据表user_myuser和auth_group之间的多对多关系,实现在用户组设置用户
  • 数据表auth_group_permissions:管理数据表auth_group和auth_permission之间的多对多关系,实现用户组设置权限。

需要注意的是:用户权限的设置只适用于非超级用户。我们在shell模式下简单介绍下用户权限设置。

#导入模型MyUser
>>> from user.models import MyUser
#查询用户信息,filter查询返回列表格式,因此设置列表索引获取User对象
>>> user = MyUser.objects.filter(username='user')[0]
#判断当前用户是否具有权限add_product
#index.add_product是固定写法,index为项目的App名, add_product是数据表auth_permission的字段codename
>>> user.has_perm('index.add_product')
False
#导入模型Permission
>>> from django.contrib.auth.models import Permission
#在权限管理表获取权限add_product的数据对象permission
>>> permission = Permission.objects.filter(codename='add_product')[0]
#对当前用户对象user 设置权限add_product
>>> user.user_permissions.add(permission)
#重新查询用户对象,判断用户权限
>>> user = MyUser.objects.filter(username='user')[0]
>>> user.has_perm('index.add_product')
True

上述代码为用户新增了一条权限,打开数据表user_myuser_user_permissions可以看到新增了一条数据。
(10) Django - Auth认证系统_第9张图片
image.png

myuser_id和permission_id分别是数据表user_myuser和auth_permission的主键。
除了添加权限外,还可以对用户的权限进行删除和查询。

>>> user = MyUser.objects.filter(username='user')[0]
>>> permission = Permission.objects.filter(codename='add_product')[0]
#删除某条权限
>>> user.user_permissions.remove(permission)
#重新查询用户对象,判断权限是否被删除
>>> user = MyUser.objects.filter(username='user')[0]
>>> user.has_perm('index.add_product')
False
#清空当前用户全部权限
>>> user.user_permissions.clear()
#将上述删除的权限添加到数据表中再查询当前权限
>>> user.user_permissions.add(permission)
>>> user.user_permissions.values()

>>>

自定义用户权限

一般情况下,每个模型默认有增(add)、改(change)、删(delete)权限,但实际开发中,可能要对某个模型设置特殊的权限,比如设置访问权限,这时候我们就需要在定义模型的时候,在模型的Meta中设置自定义权限。
对index的模型Product重新定义:

#index 的 models.py
class Product(models.Model):
    id = models.AutoField('序号', primary_key=True)
    name = models.CharField('名称',max_length=50)
    weight = models.CharField('重量',max_length=20)
    size = models.CharField('尺寸',max_length=20)
    type = models.ForeignKey(Type, on_delete=models.CASCADE,verbose_name='产品类型')
    # 设置返回值
    def __str__(self):
        return self.name

    class Meta:
        #自定义权限
        permissions = (
            ('visit_product', 'Can visit Product'),
        )

定义模型Product时,通过重写父类models.Model的permissions属性可实现自定义用户权限。该属性以元组或列表的数据格式表示,每个元素代表一个权限,也以元组或列表表示。一个权限中含有两个元素,分别是数据表auth_permission的codename和name字段。

在数据库中清除原有的数据表,重新执行数据迁移,执行完成后,打开数据表auth_permission,可以找到自定义权限visit_Product。
image.png

设置网页的访问权限

上面定义了自定义用户权限,下面介绍如何在实际开发中使用用户权限。确保数据表auth_permission已自定义权限visit_Product,数据表user_myuser分别创建了一个超级用户和一个普通用户。
首先在user 的urls.py定义URL信息

#user 的urls.py
from django.urls import path
from . import views
urlpatterns = [
    #用户登录
    path('login.html', views.loginView, name='login'),
    #用户注册
    path('register.html', views.registerView, name='register'),
    #退出登录
    path('logout.html', views.logoutView, name='logout')
    
]

然后编写对应的视图函数

from django.shortcuts import render,redirect
from .models import MyUser
from django.contrib.auth.models import Permission
from django.contrib.auth import login, authenticate, logout

def loginView(request):
    tips = '请登录'
    title = '用户登录'
    if request.method == 'POST':
        username = request.POST.get('username', '')
        password = request.POST.get('password', '')
        if MyUser.objects.filter(username=username):
            user = authenticate(username=username, password=password)
            if user:
                if user.is_active:
                    # 登录当前用户
                    login(request, user)
                return redirect('/')
            else:
                tips = '账号密码错误,请重新输入'
        else:
            tips = '用户不存在,请注册'
    return render(request, 'user.html', locals())

# 用户注册
def registerView(request):
    title = '用户注册'
    if request.method == 'POST':
        username = request.POST.get('username', '')
        password = request.POST.get('password', '')
        if MyUser.objects.filter(username=username):
            tips = '用户已存在'
        else:
            user = MyUser.objects.create_user(username=username, password=password)
            user.save()
            # 添加权限
            permission = Permission.objects.filter(codename='visit_Product')[0]
            user.user_permissions.add(permission)
            return redirect('/user/login.html')
    return render(request, 'user.html', locals())

# 退出登录
def logoutView(request):
    logout(request)
    return redirect('/')

最后编写模板文件user.html

user 的 templates 的 user.html



    
    {{ title }}
    


MyDjango Auth

{% if tips %}
{{ tips }}
{% endif %}
{% csrf_token %}
用户名:
密 码:

上述代码主要实现一个简单的操作流程,流程顺序为用户注册--->用户登录--->访问首页。
在user中实现了用户的权限设置,接着在index中实现用户权限的校验。首先编写index的urls.py文件:

#index 的 urls.py
from django.urls import path
from . import views
urlpatterns = [
    # 首页的URL
    path('', views.index),
]

然后编写对应的视图函数:

#index的views.py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required, permission_required

# 使用login_required和permission_required分别对用户登录验证和用户权限验证
@login_required(login_url='/user/login.html')
@permission_required(perm='index.visit_Product', login_url='/user/login.html')
def index(request):
    return render(request, 'index.html', locals())

在视图函数index中使用了装饰起login_required和permission_required,分别对当前用户的登录状态和用户权限进行校验。

  • login_required:设置用户登录访问权限,如果当前用户尚未登录而直接访问首页,程序自动跳转到登录界面,只有用户完成登录后才能访问首页。login_required的参数有redirect_field_name和login_url

参数redirect_field_name:默认值是next,当登录成功后,程序自动跳转回之前浏览的网页
参数login_url:设置登录界面的URL地址,默认值是settings.py的属性LOGIN_URL,而属性LOGIN_URL需要开发者自行在settings.py中配置。

  • permission_required:验证当前用户是否拥有相应的权限。若用户没有使用权限,程序会跳转到登录界面或抛出异常。permission_required的参数如下:

参数perm : 必须参数,判断当前用户是否拥有权限,参数为固定格式,如上例中index为项目的App名,visit_product来自数据表auth_permission的字段codename
参数login_url: 设置登录界面的URL地址,默认值为None,若不设置参数,验证失败后会抛出404异常。
参数 raise_exception :设置抛出异常,默认值为False

装饰器permission_required的作用与内置函数has_perm相同,上述代码也可以使用函数has_perm实现装饰器permission_required的功能。

# 使用函数has_perm实现装饰器permission_required功能
from django.shortcuts import render, redirect
@login_required(login_url='/user/login.html')
def index(request):
    user = request.user
    if user.has_perm('index.visit_Product'):
        return render(request, 'index.html', locals())
    else:
        return redirect('/user/login.html')

最后再模板index.html中实现用户权限判断。模板的

标签代码如下:

#index 的 templates 的 index.html
    {#在模版中使用user变量是一个User或者AnoymousUser对象,该对象由模型MyUser实例化#} {% if user.is_authenticated %}
  • 用户名: {{ user.username }}
  • 退出登录
  • {% endif %} {#在模版中使用perms变量是Permission对象,该对象由模型Permission实例化#} {% if perms.index.add_product %}
  • 添加产品信息
  • {% endif %}

从上述例子可以看到,项目的user主要实现权限的设置功能,项目的index主要实现权限的使用,权限的使用主要判断当前用户是否具有权限的使用资格,而权限的判断可以从视图函数或模板语法实现。

设置用户组

用户组就是对用户进行分组管理,其作用是在权限控制中批量对用户的权限进行分配,而不用一个个的按用户分配,节省维护的工作量。
设置用户组分为两个步骤:设置用户组的权限和设置用户组的用户。
我们在数据表auth_group中创建一个管理员用户组。用户组可以创建任意多个。


image.png

然后再shell模式下简单学习用户组的权限配置

#导入内置模型Group和Permission
>>> from django.contrib.auth.models import Group
>>> from django.contrib.auth.models import Permission
#获取某个权限对象permission
>>> permission = Permission.objects.get(codename='visit_product')
#获取某个用户组对象group
>>> group = Group.objects.get(id=1)
#将权限permission添加到用户组group中
>>> group.permissions.add(permission)

#当然也能删除某个权限
>>> group.permissions.remove(permission)
#删除全部权限
>>> group.permissions.clear()

然后我们再学习如何将用户分配到用户组。

#导入模型MyUser和Group
>>> from user.models import MyUser
>>> from django.contrib.auth.models import Group
#获取用户对象user,对象user代表用户名为user的数据信息
>>> user = MyUser.objects.get(username='user')
#获取用户组对象group,对象group代表用户组(管理员)的数据信息
>>> group = Group.objects.get(id=1)
#将用户添加到用户组
>>> user.groups.add(group)

#删除用户组某一用户
>>> user.groups.remove(group)
#清空用户组全部用户
>>> user.groups.clear()

你可能感兴趣的:((10) Django - Auth认证系统)