zoukankan      html  css  js  c++  java
  • 玩转Django2.0---Django笔记建站基础九(二)(Auth认证系统)

    9.4  设置用户权限

      用户权限主要是对不同的用户设置不同的功能使用权限,而每个功能主要以模型来划分。以9.3节的MyDjango项目为例,在Admin后台管理系统可以查看并设置用户权限,如下图:

     用户权限设置

      上图左边列表框中列出了整个项目的用户权限,以user|用户|Can add user为例:

        1、user代表项目的App。

        2、用户代表App所定义的模型MyUser。

        3、Can add user代表该权限可对模型MyUser执行新增操作。

      一般情况下,在执行数据迁移时,每个模型默认拥有增(add), 改(change),删(delete)权限。数据迁移完成后,可以在数据库中查看数据表auth_permission的数据信息,每条数据信息代表项目中某个模型的某个权限,如下图:

       设置用户权限实质上是对数据表user_myuser和auth_permission之间的数据设置多对多关系。首先需要了解用户、用户权限和用户组三者之间的关系,以MyDjango的数据表为例,如下图:

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

         1、数据表user_myuser_user_permissions:管理数据表user_myuser和auth_permission之间的多对多关系,实现用户权限设置。

        2、数据表user_myuser_groups:管理数据表user_myuser和auth_group之间的多对多关系,实现在用户组设置用户。

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

      实现用户的权限设置需要注意:如贵哦用户角色是超级用户,该用户是无须设置权限的,用户权限只适用于非超级用户。我们在PyCharm的Terminal下开启Django的shell模式来实现用户权限设置,代码如下:

    (py3_3) E:	est5MyDjango>python manage.py shell
    
    #导入模型MyUser
    In [1]: from user.models import MyUser
    #查询用户信息,filter查询返回列表格式,因此设置列表索引获取User对象
    In [3]: user = MyUser.objects.filter(username='user1')[0]
    #判断当前用户是否具有权限add_product
    #index.add_product为固定写法,index为项目的App名,add_product是数据表auth_permission的字段codename
    In [4]: user.has_perm('index.add_product')
    Out[4]: False
    
    #导入模型Permission
    In [5]: from django.contrib.auth.models import Permission
    
    #在权限管理表获取权限add_product的数据对象permission
    In [7]: permission = Permission.objects.filter(codename='add_product')[0]
    
    #对当前用户对象user设置权限add_product
    In [10]: user.user_permissions.add(permission)
    
    #再次判断当前用户是否具有权限add_product
    In [12]: user.has_perm('index.add_product')
    Out[12]: True

      上述代码对用户名为user1的用户设置了产品信息的新增权限,打开数据表user_myuser_user_permissions可以看到新增了一条数据,如下图:

    数据表user_myuser_user_permissions

      数据表的字段myuser_id和permission_id分别是数据表user_myuser和auth_permission的主键,如上图上的每一条数据代表某个用户具有某个模型的某个操作权限。除了添加权限之外,还可以对用户的权限进行删除和查询,代码如下:

    In [6]: user = MyUser.objects.filter(username='user1')[0]
    
    In [10]: permission = Permission.objects.filter(codename='add_product')[0]
    
    #删除某条权限
    In [11]: user.user_permissions.remove(permission)
    #判断是否已删除权限,若为False,说明删除成功。函数has_perm用于判断用户是否拥有权限
    In [12]: user.has_perm('index.add_product')
    Out[12]: False
    
    #清空当前用户全部权限
    In [13]: user.user_permissions.clear()
    
    #获取当前用户所拥有的权限信息
    #将上述删除的权限添加到数据表再查询
    In [14]: user.user_permissions.add(permission)
    
    In [15]: user.user_permissions.values()
    Out[15]: <QuerySet [{'id': 25, 'name': 'Can add product', 'content_type_id': 7, 'codename': 'add_product'}]>

    9.5  自定义用户权限

     

      一般情况下,每个模型默认拥有增(add),改(change),删(delete)权限。但实际开发中,可能要对某个模型设置特殊的权限,比如设置访问权限。为了解决这种情况,在定义模型的时候,可以在模型的Meta中设置自定义权限。以MyDjango为例,对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属性可实现自定义用户权限。该属性以元组或列表的数据格式表示,每个元素代表一个权限,也是以元组或列表表示。在一个权限中含有两个元素,如('add_Product', 'Can create Product'),add_product和Can create Product分别是数据表auth_permission的codename和name字段。

      在数据库中清除MyDjango原有的数据表,并在PyCharm的Terminal中重新执行数据迁移,指令代码如下:

    (py3_3) E:	est5MyDjango>python manage.py makemigrations
    
    (py3_3) E:	est5MyDjango>python manage.py migrate

      指令执行完成后,在数据库中打开数据表auth_permission,可以找到自定义权限visit_Product,如下图:

    自定义全visit_Product截图

     

    9.6  设置网页的访问权限

     

      本节中,结合实际的例子讲述如何在实际开发中使用用户权限,以MyDjango为例,数据表auth_permission已自定义权限visit_Product,数据表user_myuser分别创建了一名超级用户和一名普通用户,如下图:

    数据表user_myuser的用户信息

      本例需要将项目的index和user结合使用。index主要将权限应用到开发中,而user主要用于用户的注册、登录和退出登录,用于检验index的应用效果。

      首先讲解user的开发流程,我们分别对路由urls.py、视图views.py和模板user.html进行相应开发,共同完成用户的注册、登录和退出登录,代码如下:

    #路由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'),
    ]
    
    
    #视图user/views.py
    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('/')
    <!DOCTYPE html>
    <html lang="zh-cn">
    <head>
        <meta charset="utf-8">
        <title>{{ title }}</title>
        <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
    </head>
    <body>
    <div class="flex-center">
        <div class="container">
        <div class="flex-center">
        <div class="unit-1-2 unit-1-on-mobile">
            <h1>MyDjango Auth</h1>
                {% if tips %}
            <div>{{ tips }}</div>
                {% endif %}
            <form class="form" action="" method="post">
                {% csrf_token %}
                <div>用户名:<input type="text" name='username'></div>
                <div>密 码:<input type="password" name='password'></div>
                <button type="submit" class="btn btn-primary btn-block">确定</button>
            </form>
        </div>
        </div>
        </div>
    </div>
    </body>
    </html>

      上述代码主要实现一个简单的操作流程,流程顺序为用户注册->用户登录->访问首页,具体实现过程如下:

        1、首先用户访问用户注册界面,输入新的用户信息并单击"确定"按钮,提交用户注册信息到网站后台。

        2、后台的视图函数registerView接收表单数据,判断当前注册的用户是否存在。如果用户不存在,将表单数据保存到数据表user_myuser中,创建新的用户信息。

        3、默认情况下,新创建的用户是没有设置任何权限的,视图函数对新创建的用户设置visit_Product权限。注册成功后,程序会自动跳转到用户登录界面。

        4、在用户登录界面输入新创建的用户信息,完成用户登录后,程序会自动跳转到网站的首页。

      在user中实现了用户的权限设置,为新创建的用户添加visit_Product权限,接着在index中实现用户权限的校验。在index的路由urls.py、视图views.py和模板index.html中分别编写以下代码:

    #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。

          1、参数redirect_field_name:默认值是next。当登录成功之后,程序会自动跳回之前浏览的网页。

          2、参数login_url:设置登录界面的URL地址。默认值是settings.py的属性LOGIN_URL,而属性LOGIN_URL需要开发者自行在settings.py中配置。

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

          1、参数perm:必须参数,判断当前用户是否拥有权限。参数值为固定格式,如index.visit_Product,index为项目的App名,visit_product来自数据表auth_permission的字段codename。

          2、参数login_url:设置登录界面的URL地址,默认值为None。若不设置参数,验证失败后会抛出404异常。

          3、参数raise_exception:设置抛出异常,默认值为False。

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

    #使用函数has_perm实现装饰器permission_required功能
    from django.shortcuts import render, redirect
    from django.contrib.auth.decorators import login_required
    
    @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.html的<header>标签代码修改如下:

    <header id="top">
        <!-- 内容显示区域 :width : 1211px -->
        <div id="top_box">
            <ul class="lf">
                <li><a href="#">华为官网</a></li>
                <li><a href="#">华为荣耀</a></li>
            </ul>
            <ul class="rt">
                {#在模版中使用user变量是一个User或者AnoymousUser对象,该对象由模型MyUser实例化#}
                {% if user.is_authenticated %}
                    <li>用户名: {{ user.username }}</li>
                    <li><a href="{% url 'logout' %}">退出登录</a></li>
                {% endif %}
                {#在模版中使用perms变量是Permission对象,该对象由模型Permission实例化#}
                {% if perms.index.add_product %}
                    <li>添加产品信息</li>
                {% endif %}
            </ul>
        </div>
    </header>

       在模板index.html中分别使用变量user和perms,但从视图函数index总可以发现,视图函数并没有将变量user和perms传递给模板。其实变量user和perms是由Django自动生成的,变量的生成与配置五年级settings.py的TEMPLATES设置有关,我们查看setting.py的TEMPLATES配置信息,代码如下:

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates'),
                     os.path.join(BASE_DIR, 'index/templates'),
                     os.path.join(BASE_DIR, 'user/templates')]
            ,
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]

      因为TEMPLATES中定义了处理器集合context_processors,所以在解析模板Template之前,Django首先依次运行处理器集合的程序。当运行到处理器django.contrib.auth.context_processors.auth时,程序会生成变量user和perms,并且将变量传入模板变量TemplateContext中,所以在模板中可以直接使用变量user和perms。

      从上述例子可以看到,项目的user主要实现权限的设置功能;项目的index主要实现权限的使用,权限的使用主要判断当前用户是否具有权限的使用资格,而权限的判断可以从视图函数或模板语法实现。在浏览器上分别使用超级用户和普通用户登录网站,两者的首页信息如下图:

    9.7  设置用户组

      顾明思义,用户组就是对用户进行分组管理,其作用是在权限控制中可以批量地对用户的权限进行分配,而不同一个一个地按用户组所分配的所有权限。例如用户组teachers拥有权限can_create_lesson,那么所有属于teachers的用户都会有can_create_lesson权限。

      我们知道用户、权限和用户组三者之间是多对多的数据关系,而用户组可以理解为用户和权限之间的中转站。设置用户组分为两个步骤:设置用户组的权限和设置用户组的用户。

      设置用户组的权限主要对数据表auth_group和auth_permission构建多对多的数据关系,数据关系保存在数据表auth_group_permissions中。以MyDjango为例,其数据库结构如下图所示:

    数据库结构

      在数据表auth_group中创建三条数据信息:产品信息、产品类型和用户管理,每条信息在项目中代表一个用户组,如下图:

    数据表auth_group

      我们在PyCharm的Terminal中使用Django的shell模式来实现用户组的权限配置,代码如下:

    #用户组的权限配置
    #导入内置模型Group和Permission
    (py3_3) E:	est5MyDjango>python manage.py shell
    
    In [1]: from django.contrib.auth.models import Group
    
    In [2]: from django.contrib.auth.models import Permission
    
    #获取某个权限对象permission
    In [3]: permission = Permission.objects.get(codename='visit_Product')
    
    #获取某个用户组对象group
    In [4]: group = Group.objects.get(id=1)
    
    #将权限permission添加到用户组group中
    In [5]: group.permissions.add(permission)

      上述代码将visit_Product权限添加到用户组(产品信息),功能实现过程如下:

        1、从数据表auth_group获取用户组(产品信息)对象group,对象group代表数据表总某一条数据。

        2、从数据表auth_permission获取权限(visit_Product)对象permission,对象permission代表数据表中某一条数据。

        3、使用permissions.add方法将权限对象permission与用户组对象group构建多对多数据关系并保存在数据表auth_group_permissions中。查看数据表auth_group_permissions,数据信息如下图:

      

    数据表auth_group_permissions

      除了添加用户组的权限之外,还可以删除用户组已有的权限,代码如下:

    #删除当前用户组group的visit_Product权限
    In [6]: group.permissions.remove(permission)
    #删除当前用户组group的全部权限
    In [7]: group.permissions.clear()

      设置用户组的用户主要对数据表auth_group和user_myuser构建多对多数据关系,数据关系保存在数据表user_myuser_groups中。在Django的shell模式下实现用户组的用户设置,代码如下:

    #将用户分配到用户组
    #导入模型Group和MyUser
    In [8]: from user.models import MyUser
    
    In [9]: from django.contrib.auth.models import Group
    
    #获取用户对象user,对象user代表用户名为user1的数据信息
    In [11]: user = MyUser.objects.get(username='user1')
    
    #获取用户组对象group,对象group代表用户组(产品信息)的数据信息
    In [13]: group = Group.objects.get(id=1)
    
    #将用户添加到用户组
    In [14]: user.groups.add(group)

      上述代码将用户名为user1的用户添加到用户组(产品信息),功能实现过程与用户组的权限设置是相似的,只不过两者所使用的模型有所不同。查看数据表user_myuser_groups,数据信息如下图:

    数据表user_myuser_groups

      除了添加用户组的用户之外,还可以删除用户组已有的用户,代码如下:

    #删除用户组某一用户
    In [15]: user.groups.remove(group)
    #情况用户组全部用户
    In [16]: user.groups.clear()

    9.8  本章小结

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

      使用内置模型User和内置的函数可以快速实现用户管理功能,如用户注册、登录、密码修改、密码找回和用户注销。模型User的字段说明以及常用的内置函数如下。

    模型User字段及说明

    字段 说明
    ID int类型,数据表主键
    Password varchar类型,代表用户密码,在默认情况下使用pbkdf2_sha256方式来存储和管理用户的密码
    last_login datetime类型,最近一次登录的时间
    is_superuser tinyint类型,表示该用户是否拥有所有的权限,即是否为超级用户
    Username varchar类型,代表用户账号
    first_name varchar类型,代表用户的名字
    last_name varchar类型,代表用户的姓氏
    Email varchar类型,代表用户的邮件
    is_staff 用来判断用户是否可以登录进入Admin系统
    is_active tinyint类型,用来判断该账户的状态是否被激活
    date_joined datetime类型,账号的创建时间

    常用的内置函数及说明

    内置函数 说明
    authenticate 验证用户是否存在,必选参数为username和password,只能用于模型User
    create_user 创建新的用户信息,必选参数为username,只能用于模型User
    set_password 修改用户密码,必选参数为password,只能用于模型User
    login/logout 用户的登录和注销,只能哟农户模型User
    make_password 密码加密处理,必选参数为password,可脱离模型User单独使用
    check_password 检验加密前后的密码是否相同,可脱离模型User单独使用
    email_user 发送邮件,只能用于模型User
    send_mail 发送邮件
    send_mass_mail 批量发送邮件
    EmailMultiAlternatives 发送自定义内容格式的邮件

     

       Django提供了4中模型扩展的方法:

        1、代理模型:这是一种模型继承,这种模型在数据库中无须创建新数据表。一般用于改变现有模型的行为方式,如增加新方法函数等,并且不影响现有数据库的结构。当不需要在数据库中存储额外的信息,而需要增加操作方法或更改模型的查询管理方式时,适合使用代理模型来扩展现有User模型。

        2、Profile扩展模型User:当存储的信息与模型User相关,而且并不改变模型User原有的认证方法时,可定义新的模型MyUser,并设置某个字段为OneToOneField,这样能与模型User形成一对一关联,该方法称为用户配置(User Profile)。

        3、AbstractBaseUser扩展模型User:当模型User的内置方法并不符合开发需求时,可使用该方法对模型User重新自定义设计,该方法对模型User和数据库架构影响很大。

        4、AbstractUser扩展模型User:如果模型User的内置的方法符合开发需求,在不改变这些函数方法的情况下,添加模型User的额外字段,可通过AbstractUser方式实现。使用AbstractUser定义的模型会替换原有模型User。

      用户、用户权限和用户组分别对应数据表user_myuser、auth_permission和auth_group。无论是设置用户权限、设置用户所属用户组还是设置用户组的权限,其实质都是对两个数据表之间的数据建立多对多的数据关系,说明如下:

        1、数据表user_myuser_user_permissions:管理数据表user_myuser和auth_permission之间的多对多关系,实现用户权限设置。

        2、数据表user_myuser_groups:管理数据表user_myuser和auth_group之间的多对多关系,实现在用户组设置用户。

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

  • 相关阅读:
    第十九节 集群模式内各节点的通信和文件拷贝
    第十八节 虚拟机克隆后ip修改
    WAF 与 RASP 的安装使用大比拼!
    不改变中间层,如何玩转 .NET 的远程处理功能?
    什么是实时应用程序自我保护(RASP)?
    拒绝「技术栈」选择恐惧症
    为什么Nagios会那么吵?你又能做些什么呢?(1)
    Java 应用发布后,需要关注的7个性能指标
    玩转AWS CloudWatch微信告警
    日均百万 PV 的站点如何做性能监测?试试「3M口罩」!
  • 原文地址:https://www.cnblogs.com/zhaop8078/p/11603404.html
Copyright © 2011-2022 走看看