Django之权限管理插件

Posted yangziyao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django之权限管理插件相关的知识,希望对你有一定的参考价值。

参考:https://www.cnblogs.com/alex3714/articles/6661911.html

   http://www.cnblogs.com/wupeiqi/articles/6229414.html

1.      什么是权限?

权限就是对软件系统中各种资源的访问和操作的控制!

2.      什么是资源?

在软件系统中,数据库、内存、硬盘里数据都是资源,资源就是数据!

3.      动作

资源本身是静态的,必须通过合适的动作对其进行访问和操作,我们说要控制权限,其实本质上是要对访问软件中各种数据资源的动作进行控制

4.      为什么需要权限管理系统?

不同职责的工作人员对于系统操作的权限应该是不同的,不同的用户也无法窥探其他用户的信息,因此权限管理在业务中是必不可少的。

角色(组):可以对“组”进行权限分配,将权限一致的人员编入同一组,然后对该组进行权限分配。

可扩展的:它应该可以加入到任何带有权限管理功能的系统中。就像是组件一样的可以被不断的重用,而不是每开发一套管理系统,就要针对权限管理部分进行重新开发。

5.      权限管理系统的两种模式?

web开发中只有两种架构,一种是BS架构(浏览器服务端架构),另一种是CS架构(客户端服务器端架构),B/S系统中的权限比C/S中的更显的重要,C/S系统因为具有特殊的客户端,所以访问用户的权限检测可以通过客户端实现或通过客户端+服务器检测实现,而B/S中,浏览器是每一台计算机都已具备的,如果不建立一个完整的权限检测,那么一个非法用户很可能就能通过浏览器轻易访问到B/S系统中的所有功能。因此B/S业务系统都需要有一个或多个权限系统来实现访问权限检测,让经过授权的用户可以正常合法的使用已授权功能,而对那些未经授权的非法用户将会将他们彻底的拒之门外。下面就让我们一起了解一下如何设计可以满足大部分B/S系统中对用户功能权限控制的权限系统。

6.      权限管理系统的开发流程

权限条目的定义

权限条目与用户的关联

权限组件与应用的结合

7.      自定义权限

一个动作 = 一条权限 = 一个url + 一种请求方法(get/post/put...) + 若干个请求参数

请求参数是为了细化权限管理,比如我只允许你操作几行数据,或者哪一类的数据

perm_dict={
    crm_table_index:[table_index,GET,[],{},],  #可以查看CRM APP里所有数据库表
    crm_table_list:[table_list,GET,[],{}],    #可以查看每张表里所有的数据
    crm_table_list_view:[table_change,GET,[],{}],#可以访问表里每条数据的修改页
    crm_table_list_change:[table_change,POST,[],{}], #可以对表里的每条数据进行修改
    }

字典里的key是权限名,我们需要用过这些权限名来跟用户进行关联

后面values列表里第一个值如‘table_index‘django中的url_name,在这里必须相对的url name, 而不是绝对url路径,因为考虑到django url正则匹配的问题,搞绝对路径,不好控制。

values里第2个值是http请求方法

values里第3[]是要求这个请求中必须带有某些参数,但不限定对数的值是什么

values里的第4{}是要求这个请求中必须带有某些参数,并且限定所带的参数必须等于特定的值

8.      权限条目与用户的关联

我们用两种形式来实现与用户的关联,第一种形式可以使用django自带的权限管理系统,另一种是自定义数据表来实现。

          了解一下内置的权限都实现了哪些功能和创建了哪些对象,对我们自定义实现也是很有帮助的

       8.1 django自带权限管理

Django内置的权限系统包括以下三个部分:

用户(Users

许可(Permissions):用来定义一个用户(user)是否能够做某项任务(task

组(Groups):一种可以批量分配许可到多个用户的通用方式

首先最重要的开始就是User模型

User模型对应于一个用户,一个帐户,位于‘django.contrib.auth.models‘模块中。

User对象有两个多对多的属性分别是:groupsuser_permissions

User对象的ManagerUserManager

和其他的模型一样,User模型类的objects属性也是一个Manager对象,但是UserManager对象是自定义的,增加了一些方法:

create_user(username,email=None,password=None)

该方法创建保存一个is_active=TrueUser对象并返回。username不能够为空,否则抛出ValueError异常。emailpassword都是可选的。emaildomain部分会被自动转变为小写。password如果没有提供,则User对象的set_unusable_password()方法将会被调用。

make_random_password(length=10,allowed_chars=‘abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789‘)

该方法返回一个给定长度和允许字符集的密码。其中默认的allowed_chars有一些字符没有,比如i,l等等。

User对象的属性:

  username:字符串类型。必填。30个字符以内。

  first_name:字符串类型。可选。30个字符以内。

  last_name:字符串类型。可选。30个字符以内。

  email:可选。

  password:明文密码的hash或者是某种元数据。该属性不应该直接赋值明文密码,而应该通过set_password()方法进行赋值,在后面有详细说明TODO

  is_staffBoolean类型。用这个来判断是否用户可以登录进入admin site

  is_activeBoolean类型。用来判断该用户是否是可用激活状态。在删除一个帐户的时候,可以选择将这个属性置为False,而不是真正删除。这样如果应用有外键引用到这个用户,外键就不会被破坏。

  is_superuserBoolean类型。该属性用来表示该用户拥有所有的许可,而无需明确的赋予给他。

  last_logindatetime类型。最近一次登陆时间。

date_joineddatetime类型。创建时间。

         User对象方法

         is_anonymous()

永远返回False.用来将User对象和AnonymousUser(未登录的匿名用户)对象作区分用的识别方法。通常,最好用is_authenticated()方法。

        is_authenticated()

      永远返回True。该方法不代表该用户有任何的许可,也不代表该用户是active的,而只是表明该用户提供了正确的usernamepassword

        get_full_name()

      返回一个字符串,是first_namelast_name中间加一个空格组成。

        set_password(raw_password)

      调用该方法时候传入一个明文密码,该方法会进行hash转换。该方法调用之后并不会保存User对象。

        check_password(raw_password)

      如果传入的明文密码是正确的返回True。该方法和set_password是一对,也会考虑hash转换。

        set_unusable_password()

      将用户设置为没有密码的状态。调用该方法后,check_password()方法将会永远返回false。但是如果,调用set_password()方法重新设置密码后,该方法将会失效,has_usable_password()也会返回True

        has_usable_password()

      在调用set_unusable_password()方法之后,该方法返回False,正常情况下返回True

        get_group_permissions(obj=None)

      返回该用户通过组所拥有的许可(字符串列表每一个代表一个许可)。obj如果指定,将会返回关于该对象的许可,而不是模型。

        get_all_permissions(obj=None):

      返回该用户所拥有的所有的许可,包括通过组的和通过用户赋予的许可。

        has_perm(perm,obj=None)

     如果用户有传入的perm,则返回Trueperm可以是一个格式为:‘<app label>.<permission codename>‘的字符串。如果User对象为inactive,该方法永远返回False。和前面一样,如果传入obj,则判断该用户对于这个对象是否有这个许可。

        has_perms(perm_list,obj=None)

      和has_perm一样,不同的地方是第一个参数是一个perm列表,只有用户拥有传入的每一个perm,返回值才是True

        has_module_perms(package_name)

      传入的是Django app label,按照‘<app label>.<permission codename>‘格式。当用户拥有该app label下面所有的perm时,返回值为True。如果用户为inactive,返回值永远为False

        email_user(subject,message,from_email=None)

      发送一封邮件给这个用户,依靠的当然是该用户的email属性。如果from_email不提供的话,Django会使用settings中的DEFAULT_FROM_EMAIL发送。

        get_profile()

      返回一个和Site相关的profile对象,用来存储额外的用户信息。

Login Logout

得到了用户对象,接下来只需要对用户密码进行验证跳转到指定页面即可,django为我们提供了两个很好用的函数:

authenticate验证

使用命令行可以进行测试,authenticate(username,password)函数需要两个参数usernamepassword,如果校验通过则返回User对象,如果校验不通过返回None

login_required装饰器

django.contrib.auth.decorators.login_required([redirect_field_name=REDIRECT_FIELD_NAME,login_url=None])

login_required方法接受两个参数:

redirect_field_name:默认值是next。用来定义登陆成功之后的跳回之前访问界面的url

login_url:默认值是settings.LOGIN_URL。用来指定登陆界面的url。如果不传入改参数,就需要确保settings.LOGIN_URL的值是正确设置的。

许可(Permission) 和 用户组(Group)

    自己定义一些许可,就是在Model类的meta属性中添加permissions定义。比方说,创建了一个模型类叫做Discussion,我们可以创建几个权限来对这个模型的权限许可进行控制,控制某些人可以发起讨论、发起回复,关闭讨论:

      在model.py的任何一张表下增加class Meta:

class Discussion(models.Model):

     class Meta:

        permissions = (

             ("open_discussion", "Can create a discussion"),

             ("reply_discussion", "Can reply discussion"),

             ("close_discussion", "Can remove a discussion by setting its status as closed"),

)

执行manage.py syncdb就会把增加的权限信息录入到后台数据库。

通过某一个useruser_permissions属性,permission_1auth_permission表中的id值:

user.user_permissions.add(permission_1, permission_2, ...)

删除权限:

user.user_permissions.remove(permission_1, permission_2, ...)

通过user的一个组,然后通过grouppermissions属性:

group.permissions.add(permission_1, permission_2, ...)

我们要判断一个用户是否有发讨论的权限,我们可以用下面的代码:

user.has_perm(‘school.open_discussion‘)

8.2  如何利用django内置权限来管理权限呢?

答案很简单,我们只需要把写好的权限放在django自动生成的数据表即可

在model.py的任何一张表下增加class Meta:

技术分享图片

再用几行语句把权限添加到user对象中即可,django会自动帮我们把权限和用户管理起来了

user.user_permissions.add(permission_1, permission_2, ...)

或者直接在admin中操作更为快捷

技术分享图片

 

 以上操作仅仅是将用户权限名和用户关联起来了,但是具体每个权限名代表什么我们还不知道,因此,我们需要自定义一个字典来存储用户权限名和每个url,方法,参数的对应关系。

每次取到权限名再去我们的字典中取匹配

perm_dic = {
    # auth_permissions表权限    url的别名    请求方法  携带参数?name=‘2GO‘ 
    view_customer_list: [customer_list,GET,[]],
    view_customer_info: [customer_detail,GET,[]],
    edit_own_customer_info: [customer_detail,POST,[qq,nam]],
}

    因为我们可能不会使用auth中权限,所以没有必要去取回auth的所有权限名,只需要从我们的perm_dic定义好就行,每个url的别名都要对应好所需的views,所以url的名字要取得有意义

         8.3 权限组件与应用的结合

    我们希望我们的权限组件是通用的,可插拔的,它一定要与具体的业务代码分离,以后可以轻松把这个组件移植到其它的项目里去,因此这里我们采用装饰器的模式,把权限的检查、控制封装在一个装饰器函数里,想对哪个Views进行权限控制,就只需要在这个views上加上装饰器就可以了。

@check_permission
def table_change(request,app_name,table_name,obj_id):
    .....
  1. 拿到用户请求的url+请求方法+参数到我们的的perm_dic里去一一匹配
  2. 当匹配到了对应的权限条目后,就拿着这个条目所对应的权限名,和当前的用户, 调用request.user.has_perm(权限名)
  3. 如果request.user.has_perm(权限名)返回为True,就认为该用户有权限 ,直接放行,否则,则返回403页面!

下面的函数用到了url的映射函数,先简单的介绍一下

from django.urls import resolve, reverse
# resolve,reverse用来对url和name,func进行映射操作
reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
# 可以将name映射到url,参数viewname可以是任何可以调用的对象或者是url_name(在url定义的)
# 没有匹配会抛出异常raises a NoReverseMatch exceptio
# 需要传参数的时候可以在后面加,但是args和kwargs只能传递一个
# 比如在网页重定向的时候可以使用
# return HttpResponseRedirect(reverse(‘arch-summary‘, args=[1945]))

resolve(path, urlconf=None)
# 匹配成功后返回ResolverMatch对象,允许我们对解析后url的一些操作,它的属性有
# func 匹配到的函数 view_name函数对应的名称
# args,kwargs 传递的参数
# url_name?
# app_name?
# 匹配失败返回404页面

进入正题

from django.urls import resolve, reversefrom django.shortcuts import render,redirect,HttpResponse
from kingadmin.permission_list import perm_dic
from django.conf import settings


def perm_check(*args,**kwargs):

    request = args[0]
    resolve_url_obj = resolve(request.path)
    current_url_name = resolve_url_obj.url_name  # 当前url的url_name
    print(---perm:,request.user,request.user.is_authenticated(),current_url_name)
    #match_flag = False
    match_key = None
    if request.user.is_authenticated() is False:
         return redirect(settings.LOGIN_URL)

    for permission_key,permission_val in  perm_dic.items():

        per_url_name = permission_val[0]
        per_method  = permission_val[1]
        perm_args = permission_val[2]
        perm_kwargs = permission_val[3]

        if per_url_name == current_url_name: #matches current request url
            if per_method == request.method: #matches request method
                # if not  perm_args: #if no args defined in perm dic, then set this request to passed perm 

                #逐个匹配参数,看每个参数时候都能对应的上。
                args_matched = False #for args only
                for item in perm_args:
                    request_method_func = getattr(request,per_method)    # 相当于request.get 或者request.post
                    if request_method_func.get(item,None):# request字典中有此参数
                        args_matched = True
                    else:
                        print("arg not match......")
                        args_matched = False
                        break  # 有一个参数不能匹配成功,则判定为假,退出该循环。
                else:        #  for...else... 空列表
                    args_matched = True

#匹配有特定值的参数 kwargs_matched = False for k,v in perm_kwargs.items(): request_method_func = getattr(request, per_method) arg_val = request_method_func.get(k, None) # request字典中有此参数 print("perm kwargs check:",arg_val,type(arg_val),v,type(v)) if arg_val == str(v): #匹配上了特定的参数 及对应的 参数值, 比如,需要request 对象里必须有一个叫 user_id=3的参数 kwargs_matched = True else: kwargs_matched = False break # 有一个参数不能匹配成功,则判定为假,退出该循环。 else: kwargs_matched = True match_results = [args_matched,kwargs_matched] print("--->match_results ", match_results) if all(match_results): #都匹配上了 match_key = permission_key break if all(match_results): app_name, *per_name = match_key.split(_) print("--->matched ",match_results,match_key) print(app_name, *per_name) perm_obj = %s.%s % (app_name,match_key) print("perm str:",perm_obj) if request.user.has_perm(perm_obj): print(当前用户有此权限) return True else: print(当前用户没有该权限) return False else: print("未匹配到权限项,当前用户无权限") def check_permission(func): def inner(*args,**kwargs): if not perm_check(*args,**kwargs): request = args[0] return render(request,kingadmin/page_403.html) return func(*args,**kwargs) return inner 权限检查代码

9 自定义权限管理组件

  在使用django内置的权限管理操作,我们省略了最为关键的一个步骤,表结构的设计,可以说权限表结构的设计才是权限管理系统的灵魂,所有的一切都是服务于这个表结构设计的。

表结构设计如下:

from django.db import models

# Create your models here.


class User(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)
    # m = models.ManyToManyField("Role")

    class Meta:
        verbose_name_plural = 用户表

    def __str__(self):
        return self.username


# 角色表是集合了某些权限的一类人
class Role(models.Model):
    caption = models.CharField(max_length=32)

    class Meta:
        verbose_name_plural = 角色表

    def __str__(self):
        return self.caption


# 用户和角色表示多对多关系的,一个用户可以是多个角色,一个角色也可以对应多个用户,我们自建第三张多对多表便于查看
class User2Role(models.Model):
    u = models.ForeignKey(User, on_delete=True)
    r = models.ForeignKey(Role, on_delete=True)

    class Meta:
        verbose_name_plural = 用户分配角色

    def __str__(self):
        return "%s-%s" % (self.u.username,
                          self.r.caption,)


class Action(models.Model):
    # get 获取信息
    # post 创建用户
    # put 修改用户
    # delete 删除用户
    caption = models.CharField(max_length=50)
    code = models.CharField(max_length=50)

    class Meta:
        verbose_name_plural = 操作表

    def __str__(self):
        return self.caption


# menu自关联menu,因为没法确定menu的层级关系到底是多少层
class Menu(models.Model):
    caption = models.CharField(max_length=50)
    parent = models.ForeignKey(self, related_name=p, null=True, blank=True, on_delete=True)

    class Meta:
        verbose_name_plural =  菜单 

    def __str__(self):
        return self.caption


class Permission(models.Model):
    # 一个权限就是一个url加上一个动作
    # 127.0.0.1:8000/user?t=ger/post/put/delete
    caption = models.CharField(max_length=50)
    url = models.CharField(max_length=100)
    # 建立外键关系是向上查找的,如果在permission后面定义的menu就会显示差找不到
    menu = models.ForeignKey(Menu, null=True, blank=True, on_delete=True)

    class Meta:
        verbose_name_plural = URL表

    def __str__(self):
        return "%s-%s" % (self.caption, self.url,)


class Permission2Action(models.Model):
    # 真正的权限表
    p = models.ForeignKey(Permission, on_delete=True)
    a = models.ForeignKey(Action, on_delete=True)

    class Meta:
        verbose_name_plural = 权限表

    def __str__(self):
        return "%s-%s:-%s?t=%s" % (self.p.caption, self.a.caption, self.p.url, self.a.code,)


class Permission2Action2Role(models.Model):
    p2a = models.ForeignKey(Permission2Action, on_delete=True)
    r = models.ForeignKey(Role, on_delete=True)

    class Meta:
        verbose_name_plural = 角色分配权限

    def __str__(self):
        return "%s==>%s" % (self.r.caption, self.p2a,)


class Task(models.Model):
    caption = models.CharField(max_length=50)

    class Meta:
        permissions = (
            ("view_task", "Can see available tasks"),
            ("change_task_status", "Can change the status of tasks"),
            ("close_task", "Can remove a task by setting its status as closed"),
        )

将权限管理封装成一个类

from django.shortcuts import render, HttpResponse, redirect
from rabc import models
import re

# Create your views here.


class MenuHelper(object):
    def __init__(self, request, username):
        # 当前请求的request对象
        self.request = request
        # 当前用户名
        self.username = username
        # 获取当前URL,用来匹配该显示的权限和菜单
        self.current_url = request.path_info
        # 获取当前用户的所有权限
        self.permission2action_dict = None
        # 获取在菜单中显示的权限
        self.menu_leaf_list = None
        # 获取所有菜单
        self.menu_list = None

        # 用来获取或者保存在session中的数据,以免在数据库重复的取数据,无法获得实时更新的数据
        self.session_data()

    def session_data(self):
        permission_dict = self.request.session.get(permission_info)
        if permission_dict:
            self.permission2action_dict = permission_dict[permission2action_dict]
            self.menu_leaf_list = permission_dict[menu_leaf_list]
            self.menu_list = permission_dict[menu_list]
        else:
            # 获取当前用户的角色列表
            role_list = models.Role.objects.filter(user2role__u__username=self.username)

            # 获取当前用户的权限列表(URL+Action)
            # v = [
            #     {‘url‘:‘/index.html‘,‘code‘:‘GET‘},
            #     {‘url‘:‘/index.html‘,‘code‘:‘POST‘},
            #     {‘url‘:‘/order.html‘,‘code‘:‘PUT‘},
            #     {‘url‘:‘/order.html‘,‘code‘:‘GET‘},
            # ]
            # v = {
            #     ‘/index.html‘:[‘GET‘]
            # }

            # 方式一:
            # manytomany系统建表
            # role_list = models_obj.m.all()

            # 方式二 自建多对多表查询
            # user2role_list = models.User2Role.objects.filter(u = user_obj)

            # 方式三 角色表反向查询
            # role_list = models.Role.objects.filter(user2role__u=user_obj)

            # 方式四 连续跨表
            # role_list = models.Role.objects.filter(user2role__u__username=username)

            # 将重复的权限去重,并将权限放到session中,缺点:无法获取实时的权限信息
            # 或者从数据库中获取权限,缺点:如果每次都从数据库获取权限,需要每次操作数据库
            permission2action_list = models.Permission2Action.objects.                 filter(permission2action2role__r__in=role_list).                 values(p__url, a__code).distinct()

            permission2action_dict = {}
            for item in permission2action_list:
                if item[p__url] in permission2action_dict:
                    permission2action_dict[item[p__url]].append(item[a__code])
                else:
                    permission2action_dict[item[p__url]] = [item[a__code], ]

            # 获取菜单的叶子节点,即:菜单的最后一层应该显示的权限
            # 叶子节点权限menu_leaf_list,最终可以跳转的权限<a>标签,从属的父节点仅仅是可以展开
            menu_leaf_list = list(models.Permission2Action.objects.filter(permission2action2role__r__in=role_list).
                                  exclude(p__menu__isnull=True).values(p_id, p__url, p__caption, p__menu).
                                  distinct())

            # 获取所有的菜单列表
            menu_list = list(models.Menu.objects.values(id, caption, parent_id))

            self.request.session[permission_info] = {
                permission2action_dict: permission2action_dict,
                menu_leaf_list: menu_leaf_list,
                menu_list: menu_list,
            }

            # self.permission2action_list = permission2action_list
            # self.menu_leaf_list = menu_leaf_list
            # self.menu_list = menu_list

    # 处理叶子节点,将叶子节点挂靠到菜单上,并返回应该现实的树形字典
    def menu_data_list(self):
        menu_leaf_dict = {}
        open_leaf_parent_id = None

        # 归并所有的叶子节点
        for item in self.menu_leaf_list:
            item = {
                id: item[p_id],
                url: item[p__url],
                caption: item[p__caption],
                parent_id: item[p__menu],
                child: [],
                status: True,  # 是否显示,叶子节点肯定是显示的
                open: False  # 是否展开,只有拥有叶子节点的父节点才能展开,而且匹配到当前的url才需要展开
            }
            if item[parent_id] in menu_leaf_dict:
                menu_leaf_dict[item[parent_id]].append(item)
            else:
                menu_leaf_dict[item[parent_id]] = [item, ]
            if re.match(item[url], self.current_url):
                item[open] = True
                open_leaf_parent_id = item[parent_id]

        # 获取所有菜单字典
        menu_dict = {}
        for item in self.menu_list:
            item[child] = []
            item[status] = False
            item[open] = False
            menu_dict[item[id]] = item

        # 将叶子节点添加到菜单中
        # 字典中取key-value最好加items,因为如果items是其他复杂结构,没法切片和迭代
        for k, v in menu_leaf_dict.items():
            menu_dict[k][child] = v
            parent_id = k
            # 将后代中有叶子节点的菜单标记为status True
            while parent_id:
                menu_dict[parent_id][status] = True
                parent_id = menu_dict[parent_id][parent_id]

        # 将已经选中的菜单标记为【展开】
        while open_leaf_parent_id:
            menu_dict[open_leaf_parent_id][open] = True
            open_leaf_parent_id = menu_dict[open_leaf_parent_id][parent_id]

        # 生成树形结构数据
        result = []
        for row in menu_dict.values():
            if not row[parent_id]:
                result.append(row)
            else:
                menu_dict[row[parent_id]][child].append(row)
        return result

    def menu_content(self, child_list):
        response = ""
        tpl = """
            <div class="item %s">
                <div class="title">%s</div>
                <div class="content">%s</div>
            </div>
        """
        for row in child_list:
            if not row[status]:
                continue
            active = ""
            if row[open]:
                active = "active"
            # 有url的子项是权限项
            if url in row:
                response += "<a class=‘%s‘ href=‘%s‘>%s</a>" % (active, row[url], row[caption])
            else:
                title = row[caption]
                content = self.menu_content(row[child])
                response += tpl % (active, title, content)
        return response

    def menu_tree(self):
        response = ""
        tpl = """
        <div class="item %s">
            <div class="title">%s</div>
            <div class="content">%s</div>
        </div>
        """
        for row in self.menu_data_list():
            if not row[status]:
                continue
            active = ""
            if row[open]:
                active = "active"
            # 第一层第一个
            title = row[caption]
            # 第一层第一个的后代
            content = self.menu_content(row[child])
            response += tpl % (active, title, content)
        return response

    def actions(self):
        """
        检查当前用户是否对当前URL有权访问,并获取对当前URL有什么权限
        """
        action_list = []
        # 当前所有权限
        # {
        #     ‘/index.html‘: [‘GET‘,POST,]
        # }
        # 如果想把权限扩展到具体的几行数据,那么权限管理表中额外的添加参数
        for k, v in self.permission2action_dict.items():
            if re.match(k, self.current_url):
                action_list = v  # [‘GET‘,POST,]
                break
        return action_list


def permission(func):
    def inner(request, *args, **kwargs):
        user_info = request.session.get(user_info)
        if not user_info:
            return redirect(/login.html)
        obj = MenuHelper(request, user_info[username])
        action_list = obj.actions()
        if not action_list:
            return HttpResponse(无权限访问)
        kwargs[menu_string] = obj.menu_tree()
        kwargs[action_list] = action_list
        return func(request, *args, **kwargs)
    return inner


def login(request):
    if request.method == "GET":
        return render(request, login.html)
    else:
        username = request.POST.get(username)
        pwd = request.POST.get(pwd)
        obj = models.User.objects.filter(username=username, password=pwd).first()
        if obj:
            # obj.id,  obj.username
            # 当前用户信息放置session中
            request.session[user_info] = {nid: obj.id, username: obj.username}

            # 获取当前用户的所有权限
            # 获取在菜单中显示的权限
            # 获取所有菜单
            # 放置session中
            MenuHelper(request, obj.username)
            return redirect(/index.html)
        else:
            return redirect(/login.html)


def logout(request):
    request.session.clear()
    return redirect(/login.html)


@permission
def index(request, *args, **kwargs):
    action_list = kwargs.get(action_list)
    menu_string = kwargs.get(menu_string)
    if "GET" in action_list:
        result = models.User.objects.all()
    else:
        result = []
    return render(request, index.html, {menu_string: menu_string, action_list: action_list})

menuhelper类里封装了所有我们需要的信息,我们只要在装饰器中调用它,并把所需要的参数传出来即可。

      

 

 

 

 





以上是关于Django之权限管理插件的主要内容,如果未能解决你的问题,请参考以下文章

django报障系统之解决工单和报表

Django之管理权限

[Django]用户权限学习系列之设计自有权限管理系统设计思路

Django web框架之权限管理一

django之权限管理公共组件

Django REST框架--认证和权限