第十章笔记——Auth认证系统

一般表单类存储到模型的难点在于外键的存在
可用shell来查找问题所在(上上一章遗留,第8章)

CharField也可以写数字,但会自动转换成字符串

Auth认证系统

用户信息: auth_user
用户权限:ayuth_permission
用户组:auth_group

django内置User模型一共定义了11个字段

待补

注册

User模型

 # create_user是模型User特有的函数,改函数创建并保存一个is_active=True的User对象,其中username不能为空
写入数据库(使用save()),模型User的其他字段还可作为create_user的可选参数

登录

内置模型authenticate完成账户密码的验证过程

     if user.is_active: # is_active字段判断用户是否被激活,is_active为1责备激活
                    login(request, user) # login()函数接收2个参数,一个是request对象,一个是user对象

修改密码

user.set_password(p2) # 用这个来判断原始密码是否正确么

函数set_password是在内置函数make_password的基础上进行封装而来的。django默认使用pbkdf2_sha256方式存储和管理用户密码,而内置函数make_password用于实现用户密码的加密处理,并且改函数可以脱离Auth认证系统单独使用,比如对某些特殊数据进行加密处理。
使用make_password一般都是先加密密码,然后再user.password=xxx加密后的密码,然后再用save()方法保存到数据库中即可。
内置函数check_password,可对加密前的密码和加密后的密码进行验证匹配,判断两者是否为同一密码。两个参数分别是加密前的密码和加密后的密码。

用户注销,退出登录

def logoutView(request): # request用户请求对象
    # logout是内置函数
    logout(request) # 这个视图时直接判断,然后跳转么
    return HttpResponse('注销成功')

发送邮件实现密码找回

settings.py的配置邮件信息

# 邮件配置信息
EMAIL_USE_SSL = True
# 邮件服务器,如果是 163就改成 smtp.163.com
EMAIL_HOST = 'smtp.qq.com'
# 邮件服务器端口
EMAIL_PORT = 465
# 发送邮件的账号
EMAIL_HOST_USER = 'xxxx@qq.com'
# SMTP服务密码
EMAIL_HOST_PASSWORD = 'dexxxvddfh'
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER

下方的是基于django后台注册时候填写的邮箱账号为接收账号的

# 找回密码;这里发送邮箱的地址是你注册时候填写的地址
def findpsView(request):
    button = '获取验证码'
    VCodeInfo = False
    password = False
    if request.method == 'POST':
        u = request.POST.get('username')
        VCode = request.POST.get('VCode', '')
        p = request.POST.get('password')
        user = User.objects.filter(username=u)
        # 用户不存在
        if not user:
            tips = '用户' + u + '不存在'
        else:
            # 判断验证码是否已发送
            if not request.session.get('VCode', ''):
                # 发送验证码并将验证码写入session
                button = '重置密码'
                tips = '验证码已发送'
                password = True
                VCodeInfo = True
                VCode = str(random.randint(1000, 9999)) # 随机生成长度为4的验证码
                # 会话session
                request.session['VCode'] = VCode # 写入会话Session的VCode,其作用是与用户输入的验证码进行匹配
                # email_user函数发送验证密码;模型User特有的方法
                user[0].email_user('找回密码', VCode) #发送邮件的方式email_user
            # 匹配输入的验证码是否正确,发送完毕之后爱匹配,可写在if之后
            elif VCode == request.session.get('VCode'):
                # 密码加密处理并保存到数据库
                dj_ps = make_password(p, None, 'pbkdf2_sha256') # p是你输入的密码
                user[0].password = dj_ps # 利用加密处理重置就可以保存密码了
                user[0].save()
                del request.session['VCode']
                tips = '密码已重置'
            # 输入验证码错误
            else:
                tips = '验证码错误,请重新获取'
                VCodeInfo = False
                password = False
                del request.session['VCode']
    return render(request, 'user.html', locals())

除了使用内置函数email_user发送邮件(模型User的),其他方式

待补
### send_mass_mail
### EmailMultiAlternatives

用shell来发送邮件

应该只能发送一个管理员注册时候的账号,若通过DEFAULT_FROM_EMAIL

DEFAULT_FROM_EMAIL

默认: 'webmaster@localhost'
用于来自站点管理员的各种自动通信的默认电子邮件地址。这不包括发送到ADMINS 和的错误消息MANAGERS;为此,请参阅SERVER_EMAIL。

In [1]: from django.core.mail import send_mail

In [2]: from django.conf import settings

In [3]: from_email = settings.DEFAULT_FROM_EMAIL

In [4]: sending = ['xxx@qq.com']

In [5]: send_mail('django_test','打扰',from_email,sending)

User模型的扩展与使用

django提供了4种模型扩展扩展的方法
代理模型:
一种模式继承,这种模型在数据库种无需创建新数据表。一般用于改变现有模型的行为方式,如增加新方法函数等,并且不影响数据表的结构。如果不需要在数据表存储额外的信息,只是增加模型User的操作方法或更改模型的查询方式,那么可以使用代理模型扩展模型User.
Profile扩展模型User":

待补

AbstractBaseUser扩展。。。

待补

AbstractUser扩展。。。

待补

User的源文件

django/contrib/auth/models.py
模型User继承自AbstractUser

class User(AbstractUser):
pass

而AbstractUser继承自AbstractBaseUser和PermissionsMixin

class AbstractUser(AbstractBaseUser, PermissionsMixin):
pass

模型User的字段和方法是由父类AbstractUser,AbstractBaseUser和PermissionsMixin定义的。
使用AbstractUser来扩展User

自定义表单类来实现模型绑定在后台页面上;

from django.contrib.auth.forms import UserCreationForm
from .models import MyUser

这个需要好好研究,在书本的第255页
class MyUserCreationForm(UserCreationForm):
    class Meta(UserCreationForm.Meta):
        model = MyUser
        # 在注册界面添加邮箱、手机号码、微信号码和QQ号码
        fields = UserCreationForm.Meta.fields
        fields += ('email', 'mobile', 'weChat', 'qq')

权限的设置与使用

在后台管理界面中每个权限以
'项目应用|模型|模型使用权限'的格式展现
设置用户权限实际上是对数据表user_myuser(自定义User类的实例数据表,和auth_user数据表等价)和auth_permission之间的数据设置多对多关系

用户、用户组、权限三者关系

无论是设置用户权限,设置用户所属用户组或者设置用户组的权限,他们的本质都是对两个数据表之间的数据建立多对多的数据关系,说明如下:(auth_user是下方的user_myuser)
数据表user_myuser_user_permissions:管理数据表user_myuser和auth_permission之间的多对多关系,设置用户所拥有的权限
数据表user_myuser_groups:管理数据表user_myuser和auth_group之间的多对多关系,设置用户所在的用户组
数据表auth_group_permissions:管理数据表auth_group和数据表auth_permission之间的多对多关系,设置用户组所在的权限。

用django的shell模式实现用户权限设置

未整理,观感欠佳

In [1]: from user.models import MyUser

In [2]: user = MyUser.objects.filter(username='xinbancan')

In [3]: #

In [4]: # 判断当前用户是否具有用户新增的权限

In [5]: # user.add_myuser为固定写法

In [6]: user为项目应用的名称
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-6-1b175a0fa344> in <module>
----> 1 user为项目应用的名称

NameError: name 'user为项目应用的名称' is not defined

In [7]: # add_myuser来自数据表auth_permission的字段codename

In [8]: user.has_perm('user.add_myuser')
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-f956f40c0fc8> in <module>
----> 1 user.has_perm('user.add_myuser')

AttributeError: 'QuerySet' object has no attribute 'has_perm'

In [9]: # 直接报错,缘由它的权限为空

In [10]: # 导入模型Permission

In [11]: from django.contrib.auth.models import permission
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-11-ee3691ae7171> in <module>
----> 1 from django.contrib.auth.models import permission

ImportError: cannot import name 'permission'

In [12]: from django.contrib.auth.models import Permission

In [13]: # 在权限管理表获取权限add_myuser的数据对象permission

In [14]: p = Permission.objects.filte(codename='add_group')
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-14-e760cdecd143> in <module>
----> 1 p = Permission.objects.filte(codename='add_group')

AttributeError: 'PermissionManager' object has no attribute 'filte'

In [15]: p = Permission.objects.filter(codename='add_group')

In [16]: # 对当前用户对象user设置权限add_myuser

In [17]: # 该字段由内置模型User的父类PermissionsMixin定义

In [18]: p = Permission.objects.filter(codename='add_myuser')

In [19]: user.user_permissions.add(p)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-19-62527e976675> in <module>
----> 1 user.user_permissions.add(p)

AttributeError: 'QuerySet' object has no attribute 'user_permissions'

In [20]: user = MyUser.objects.filter(username='xinbancan1')

In [21]: user.user_permissions.add(p)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-21-62527e976675> in <module>
----> 1 user.user_permissions.add(p)

AttributeError: 'QuerySet' object has no attribute 'user_permissions'

In [22]: # 总之这个就是你没有权限,我用shell把该权限提取出来,然后赋值给你

自定义用户权限

在models.py中设定

    class Meta(AbstractUser.Meta):# 这章是为了自定义用户权限
        # 自定义权限
        permissions = ( # 元组或列表形式展示,元组或列表的每个元素代表一个权限,每个权限以元组或列表表示
            ('vip_myuser', 'Can vip user'), # 把这个权限加入到和增删改查同级别权限么
        ) # 一个权限种含有两个元素,分别表示数据表auth_permission的codename字段和name字段

设置用户的访问权限

就是设定一个登录界面在跳转么,采用装饰器判断用户在页面跳转的时候是否符合下一个页面的条件,那这里肯定采用了session,他在哪呢

# login_required判断用户是否已登录。
# permission_required判断当前用户是否具备某个权限
@login_required(login_url='/login.html')
@permission_required(perm='user.vip_myuser', login_url='/login.html')
def infoView(request):
    return render(request, 'info.html', locals())

上述两个函数作用及参数


# login_required判断用户是否已登录。无登录,则跳转到登录界面
# 4个参数,function,默认值为None,这是定义装饰器的执行函数;redirect_field_name:默认值是next,当登录成功后,程序会自动跳回之前浏览的网页
# login_url:设置用户登录的路由地址,默认值是settings.py中的配置属性,而配置属性LOGIN_URL需要开发者自行配置
# permission_required判断当前用户是否具备某个权限
# 参数perm:必选参数,判断当前用户是否具备某个权限;参数login_url为设置验证失败之后的跳转路由,默认值为None,若不设置,则跳转失败后会抛出404异常
# raise_exception:设置抛出异常,默认值为False

django解析模板文件自动生成的模型变量user和perms

变量user和perms分别是用户和权限表单,即auth_user(自定义用户管理则是其他表单),auth_permission
有时候视图函数中并没有定义变量,但有些变量是可以在Django解析模板文件的过程中生成的,他们与配置文件settings.py文件的Templates设置有关;这里的auth就是内置模型User。若你设置了自定义用户管理,也就是导入了这个模块,那么你的models.py在实例化时会生成这两个变量,即数据表的实例化

 'OPTIONS': {
            'context_processors': [ # 处理器集合
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth', # 运到到auth程序时,会生成变量user和perms,并将变量传入模板上下文TemplateContext中
                'django.contrib.messages.context_processors.messages',
            ],

用户组的设置与使用

用户组是对用户进行分组管理,其作用是在权限控制中可以批量的对用户权限进行分配,无需将权限一个一个分配到每个用户,节省维护的工作量。将用户加入某个用户组,该用户就拥有该用户组所具备的权限。
用户组看可以理解为用户和权限之间的中转站。
设置用户组分为两个步骤,设置用户组的权限和设置用户组的用户。

对用户组进行权限分配

In [1]: # 用户组的权限配置

In [2]: # 导入内置模型Group和Permission

In [3]: from django.contrib.auth.models import Group

In [4]: from django.contrib.auth.models import Permission

In [5]: # 内置的auth表名开头都大写,去表auth

In [6]: # 获取权限对象p

In [7]: p = Permission.objects.get(codename='vip_myuser')

In [8]: # 获取某个用户组group

In [9]: group = Group.objects.get(id=1)

In [10]: # 将权限对象P添加到用户组group中

In [11]: group.permissions.add(p)
# 在auth_group_permissions表中就会生成如下的数据表
"id"	"group_id"	"permission_id"	"NAVICAT_ROWID"
"1"	"1"	"25"	"1"
# 删除当前用户组group的vip_myuser权限
 group.permissions.remove(p)
# 在auth_group_permissions表下生成的数据就会消失
In [13]: # 删除当前用户组group的全部权限

In [14]: group.permissions.clear()

实现用户组的用户分配

这个过程是对auth_group和user_myuser构建多对多的数据关系,数据关系保存在数据表user_myuser_groups中。

In [15]: # 导入模型Group和MyUser

In [16]: from user.models import MyUser

In [17]: from django.contrib.auth.models import Group

In [18]: # 获取用户对象user,代表用户名为user1的数据信息

In [19]: user = MyUser.objects.get(username='user1')

In [20]: # 获取用户组group

In [21]: group = Group.objects.get(id=1)

In [22]: # 将用户添加到用户组

In [23]: user.groups.add(group)

In [24]: # 删除用户组某用户

In [25]: user.groups.remove(group)

In [26]: # 删除用户组全部用户

In [27]: user.groups.clear()

笔记来源:Django Web应用开发实战

posted @ 2021-11-26 18:28  索匣  阅读(223)  评论(0编辑  收藏  举报