基于Django认证系统的权限管理开发

基于Django认证系统的权限管理开发

当我们开发一个Web系统时,不可避免要设计用户管理系统,实现用户注册与登录、用户认证、权限分配、密码修改等功能。Django在框架中内置了一个强大的认证系统,集成了用户登录、登出、验证、权限分配等模块,并实现了基于cookie的用户会话。

Django认证系统简介

Django认证系统既能验证身份,也能核准权限。简单来说,身份验证用于核实某个用户是否合法,而权限核准是指通过身份验证的用户能做什么,认证系统就是实现这两个任务的系统。

认证系统基本知识

Django内置了强大的用户认证auth模块,系统默认使用auth_user表来存储用户数据。通过from django.contrib import auth导入,auth模块提供了许多函数用于认证,主要有:

  • authenticate(username='username',password='password'):提供了用户认证功能,即验证用户名和密码是否正确,参数为username、password;如果认证成功会返回一个User对象。

  • login(HttpRequest,user):实现用户登录功能,参数为HttpRequest对象和一个经过认证的User对象。

    使用login()登录,request.user就能取得当前登录的用户对象,如果未登录,取得的是一个匿名用户对象AnonymousUser对象。

  • is_authenticated():判断当前请求是否通过了认证。

  • logout(request):清除当前请求的全部session。

  • create_user():创建新用户,至少提供用户名和密码。

  • set_password(password):修改密码。

  • check_password(password):检查密码是否正确。

  • 另外还有一个login_required装饰器,通过该装饰器能够使视图函数首先判断用户是否登录。如果未登录,网页会跳转到settings设置的LOGIN_URL参数对应的URL。

默认权限设置

当我们为应用程序创建一个应用程序并迁移数据模型到数据库后,Django认证系统默认给这个数据模型设置4个权限,分别是view、add、change、delete。

Django用User、Group、和Permission完成权限管理,实现方式是将属于数据模型的某个Permission对象赋予User或Group。如果把权限赋予某个User对象,那么这个用户对象就有这个权限;如果把权限赋予某个Group对象,那么属于这个组的所有用户就拥有了这个权限。

创建自定义权限的方法

Django中添加权限方式有两种,一种是通过数据模型,另一种是用代码创建。

  1. 通过定义数据模型增加权限,在定义模型时,可以在Meta中定义权限:

    class test(models.Model):
        name = models.CharfField(max_length=32)
        class Meta:
            permissions = [
                ('add_test','在test表中增加记录的权限'),
            ]
    

    在执行数据库迁移命令后会增加一条权限,权限的名字一般是APP_name.Perssion_name的形式

  2. 通过代码增加权限,权限是django.contrib.auth.Perssion的实例对象,可理解为权限记录保存在Permission表中,它包含name、codename、content_type3个字段,其中的content_type与数据模型相关联,可以理解为content_type表示一个权限在哪个应用程序中的哪个数据模型中定义:

    from django.http import HttpResponse
    from . import models
    from django.contrib.auth.models import Permission,ContentType
    def add_permission(request):
        content_type = ContentType.object.get_for_model(model.test)
        permission = Permission.objects.create(codename='add_test',name='在 test表中增加记录的权限',content_type=content_type)
        return HttpResponse('ok')
    

基于Django认证系统的权限管理开发

在项目test_orm下新建test_auth应用。

创建能增加权限的数据模型

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import Permission

class authority(models.Model):
    codename = models.CharField("权限代码", max_length=32)
    url = models.CharField('URL配置项名称', max_length=128)
    name = models.CharField('权限描述', max_length=120)

    def save(self, *args, **kwargs):
        # 取得content_type对象,该对象与test_auth中的authority数据模型有关联
        content_type_obj = ContentType.objects.get(app_label='test_auth', model='authority')
        # 增加一个权限,权限代码与字段codename的值相同,权限名与字段name的值相同
        permission = Permission.objects.create(codename=self.codename,
                                               name=self.name,
                                               content_type=content_type_obj)
        super(authority, self).save(*args, **kwargs)  # 调用父类的 save 方法将数据保存到数据库中
    def delete(self, *args,**kwargs):
        content_type_obj = ContentType.objects.get(app_label='test_auth', model='authority')
        permission=Permission.objects.get(codename=self.codename,
                              content_type=content_type_obj)
        # 删除权限
        permission.delete()
        super(authority, self).delete(*args, **kwargs)


    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '权限表'
        verbose_name_plural = verbose_name

说明:

以上代码建立了数据模型authority,重写数据模型的save方法,实现了每增加一条记录就增加一个权限。该权限的权限代码取当前记录的codename字段的值,权限名取name字段值。重写了数据模型的delete方法,实现了每删除一条记录就删除权限代码,等于删除这条记录的codename字段值的权限。

注册数据模型

为了能让Django Admin管理数据模型authority,在admin文件对数据模型进行注册:

from django.contrib import admin
from . import models

class authorityadmin(admin.ModelAdmin):
    list_display = ('codename','url','name')
# Register your models here.
admin.site.register(models.authority,authorityadmin)

建立测试系统

为了对权限设置、分配进行测试我们先建立一个测试系统。首先对这个系统的URL进行梳理,整理出权限信息记录并输入authority,然后分配给用户组或用户,最后登录这个测试系统查看权限管理是否发挥作用。

测试系统视图函数

views中加入:

from django.http import HttpResponse
from django.shortcuts import render,redirect
from django.contrib.auth import authenticate, login

# Create your views here.
def user_login(request):
    if request.method == "GET":
        return render(request, "test_auth/login.html")
    else:
        username = request.POST.get("username")
        password = request.POST.get("password")
	    # 验证是否是系统认证用户
        user_obj = authenticate(username=username, password=password)
        if user_obj:
            login(request, user_obj)
            return redirect("/test_auth/index/")
        else:
            return render(request, "test_auth/login.html")

def logout(request):
    request.session.clear()
    return redirect('/test_auth/user_login/')



def index(request):
    return render(request, "test_auth/index.html")


def userinfo(request):
    data_list = [
        {"id": 1, "name": "张三","work":"律师"},
        {"id": 2, "name": "李四","work":"教师"},
        {"id": 3, "name": "王五","work":"程序员"},
        {"id": 4, "name": "赵六","work":"医生"},
        {"id": 5, "name": "田七","work":"小护士"},
    ]

    return render(request, "test_auth/userinfo.html", {"data_list": data_list})


def userinfo_add(request):
    if request.method == "GET":
        return render(request,"test_auth/useradd.html")
    else:
        return redirect("/test_auth/userinfo/")#redirect中的/urserinfo/对应的是网址,前有/是绝对地址,前无/相对地址


def userinfo_del(request, nid):
    return HttpResponse("删除用户")


def userinfo_edit(request, nid):
    return HttpResponse("编辑用户")


def department(request):

    return render(request,"test_auth/department.html")


def department_add(request):
    return HttpResponse("添加部门")


def department_del(request, nid):
    return HttpResponse("删除部门")


def department_edit(request, nid):
    return HttpResponse("编辑部门")

测试系统母版

{% load static %}
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width">
    <title>首页</title>
    <link href="{% static 'bootstrap/css/bootstrap.min.css' %}" rel="stylesheet">
    <script src="{% static 'jquery-3.3.1.js' %}"></script>


    </script>
</head>
<body>
<div >
    <div style="float: left;width: 20%;height: 900px;background-color: darkgrey">
    <h4 >&nbsp;&nbsp;菜单栏</h4>
    <br>

      <ul class="nav nav-sidebar">
          		<!-- 判断当前用户是否有部门信息查看权限-->
                {% if perms.test_auth.department_list %}
                <li ><a href="/test_auth/department/">部门信息管理</a></li>
                {% endif %}
                  {% if perms.test_auth.userinfo_list %}
                <li><a href="/test_auth/userinfo/">用户信息管理</a></li>
                 {% endif %}
            </ul>
        <a type='button' href='/logout/' class='btn btn-primary'>退出</a>
    </div>
    <div style="float: left;width: 80%">
        {% block content %}

        {% endblock %}
    </div>
</div>


</body>
</html>

用户列表页面

{% extends 'test_auth/base.html' %}
{% block content %}

<div align="center">


<h2>用户查看</h2>

    <p></p>
        <table border="1" width="600px">
            <thead>
                <th>编号</th>
                <th>姓名</th>
                <th>职业</th>
                <th>允许的操作</th>
            </thead>
            <tbody>
            {% for row in data_list %}
                <tr>
                    <td>{{ row.id }}</td>
                    <td>{{ row.name }}</td>
                     <td>{{ row.work }}</td>
                    <td>
                        <!--判断当前用户是否有用户信息编辑权限 -->
                        {% if perms.test_auth.userinfo_edit %}
                         <a href="/test_auth/userinfo/edit/12/">编辑</a>
                        {% endif %}
                        {% if perms.test_auth.userinfo_del %}
                        <a href="/test_auth/userinfo/del/12/">删除</a>
                        {% endif %}

                    </td>
                </tr>
            {% endfor %}
            </tbody>
        </table>
    <br>

      {% if perms.test_auth.userinfo_add %}
     <a href="/test_auth/userinfo/add/">添加用户</a>
    {% endif %}

    </div>
{% endblock %}

测试系统URL配置

一级URL:

path('test_auth/',include('test_auth.urls')),

二级URL:

from django.urls import path
from . import views

urlpatterns = [
    path('user_login/', views.user_login,name='user_login'),
    path('logout/', views.logout,name='logout'),
    path('index/', views.index,name='index'),
    path('userinfo/', views.userinfo,name='userinfo_list'),
    path('userinfo/add/', views.userinfo_add,name='userinfo_add'),
    path('userinfo/del/(\d+)/', views.userinfo_del,name='userinfo_del'),
    path('userinfo/edit/(\d+)/', views.userinfo_edit,name='userinfo_edit'),

    path('department/', views.department,name='department_list'),
    path('department/add/', views.department_add,name='department_add'),
    path('department/del/(\d+)/', views.department_del,name='department_del'),
    path('department/edit/(\d+)/', views.department_edit,name='department_edit'),
]

每一个配置项就是一个权限资源。

权限梳理与分配

我们采用直接简便的方法,把测试系统的URL配置项作为权限记录整理出来,输入authority表,然后建立用户、分配权限。

权限记录整理

根据urls中的配置项整理出权限代码并按照authority表字段格式形成表格:

权限代码 URL配置项名 权限描述
department_del department_del 部门信息删除
department_add department_add 部门信息增加
department_list department_list 部门信息查看
userinfo_edit userinfo_edit 用户信息修改
userinfo_del userinfo_del 用户信息删除
userinfo_add userinfo_add 用户信息增加
userinfo_list userinfo_list 用户信息查看

权限记录输入

通过python manage.py createsuperuser命令建立超级用户,用这个超级用户进行权限信息输入、建立用户组和用户、分配权限。

根据上表输入系统,用超级用户登录Django Admin管理后台,在authority表中输入权限记录。

权限分配

在Django Admin管理后台建立一个用户并对用户分配权限:

测试系统

用新建的用户登录测试系统,用户界面按照权限的设置进行了显示。

本章介绍的基于Django认证系统的权限管理开发仅提供了解决方案和思路。其实还可以进一步完善,如可以在用户登录后,在登陆视图函数里把用户的权限放在session中,通过组合session中的数据,动态生成主页的菜单。

posted @ 2021-08-03 21:12  KKKyrie  阅读(450)  评论(0编辑  收藏  举报