Django的Rbac介绍2详解编程语言

上一篇博客我们记录了一下Django中使用Rbac,但是上一篇博客中的方法有一点不好,就是,因为我要在html文件中控制:如果用户有某个权限,则显示这个权限所代表的按钮,但是我现在只有1张表的增删改查,但是如果我有多张表呢,我难道要每张表都写一次类似下面的代码吗?

                     {%  if "/user/del/(/d+)" in per_list %} 
                        <a href="/user/del/{{ user.id }}"><button type="button" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span>&nbsp删除</button></a> 
                     {% endif %} 

  

这样就必须麻烦了,因为上面是user表,如果我还有一张role的表,我是不是也要在写一遍呢?

                     {%  if "/roles/del/(/d+)" in per_list %} 
                        <a href="/user/del/{{ user.id }}"><button type="button" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span>&nbsp删除</button></a> 
                     {% endif %} 

  

可能有的同学会说:我当然要每张表写一次了,但是大家是否可以想一想,不论是roles表还是user表,或者是其他的表,他们的权限是不是都是一样的,永远都逃不出增删改查4个权限,那么我们就可以从这里入手来进行优化

针对上面的问题,我们可以下面的方式解决

1、首先我们需要重新设计数据库

用户表如下,这张表我们没有做任何改动,和方法1是一样的

class Userinfo(models.Model): 
    username = models.CharField(max_length=64) 
    uerpwd = models.CharField(max_length=64) 
    roles = models.ManyToManyField(to="Role") 
 
    def __str__(self): 
        return self.username 
    class Meta: 
        verbose_name = "用户表" 
        verbose_name_plural = verbose_name 

  

角色表如下,这张表我们没有做任何改动,和方法1是一样的

class Role(models.Model): 
    title = models.CharField(max_length=64) 
    pers = models.ManyToManyField(to="per") 
 
 
    def __str__(self): 
        return self.title 
    class Meta: 
        verbose_name="角色表" 
        verbose_name_plural = verbose_name 

  

下面的表,我们就和方法1不一样的了

首先我们看下权限表

class per(models.Model): 
    title = models.CharField(max_length=64) 
    url = models.CharField(max_length=128) 
    action = models.CharField(max_length=32, default="") 
    group = models.ForeignKey("PerGroup", default=1) 
    def __str__(self): 
        return self.title 
    class Meta: 
        verbose_name = "权限表" 
        verbose_name_plural = verbose_name 

  

权限表我们增加了2个字段

Django的Rbac介绍2详解编程语言

action字段描述的就是四种操作,增删改查,比如list就是查,del就删,edit就是改,add就是增加

group字段描述的就是我这个权限属于哪张表,比如属于用户表,或者权限表

所有我们这里还需要增加一张表

class PerGroup(models.Model): 
    title = models.CharField(max_length=32) 
 
    def __str__(self): return self.title 
 
    class Meta: 
        verbose_name = "权限组" 
        verbose_name_plural = verbose_name 

  

2、下面我们看下在登陆的视图函数中是如何处理权限的,到底把哪些信息放到session中了

 # 2、方案2,是我们重新设计数据库后的方法 
            obj  = userobj.roles.all().values("pers__url","pers__group_id","pers__action") 
 
            print(obj) 
            # print(dir(request.session)) 
            # print("=" * 120) 
            # return redirect("/user/") 
 
            # 构建一个这样的数据结构 
            per_dict = {} 
            for item in obj: 
 
                gid = item.get("pers__group_id") 
                if gid in per_dict.keys(): 
                    per_dict[gid]["urls"].append(item["pers__url"]) 
                    per_dict[gid]["action"].append(item["pers__action"]) 
                else: 
                    per_dict[gid] = { 
                        "urls":[item["pers__url"],], 
                        "action" :[item["pers__action"],] 
                    } 
            request.session["per_dict"] = per_dict 
 
            return HttpResponse("登陆成功") 
        else: 
            return render(request, "rbac_login.html") 

  

我们实际构建了一个这样的字典,然后把这个字典放到session中

{

“group_id1”:{

  action:[aa,bb,cc],

  urls:[aa,bb,cc],

}

“group_id2”:{

  action:[aa,bb,cc],

  urls:[aa,bb,cc]

}

}

3、然后我们看下中间件函数是如何处理的

        per_dict = request.session.get("per_dict") 
        print(per_dict) 
        for item in per_dict.values(): 
            urls = item["urls"] 
            for reg in urls: 
                reg = "^" + reg + "$" 
 
                ret = re.match(reg,current_path) 
                if ret: 
                    print("action",item["action"]) 
 
                    # 为request对象赋值一个新的变量 
                    request.actions =  item["action"] 
 
                    return None 
        return HttpResponse("无权限访问") 

这里还有一个知识点,我们为request这个对象赋值了一个变量,那么以后所有request这个对象都可以去获取action这个变量的值

Django的Rbac介绍2详解编程语言

其实这里和方法1是没有区别的,都是从session中取出urls的信息,然后和当前的url进行对比,如果能匹配上,则通过。如果匹配不上,则返回无权限

4、重点是在这里,主要是在html中处理就会简单一些

我们先看下视图函数是如何渲染html页面的

def user(request): 
    userobj = rbacmodels.Userinfo.objects.all() 
 
 
    # 方案1的代码处理逻辑 
    # per_list = request.session.get("per_list") 
    # print(per_list) 
    # return render(request,"rbac_user.html",{"user_list":userobj,"per_list":per_list}) 
 
 
    # 方案2的代码处理逻辑 
    uid = request.session.get("userid") 
    # user = rbacmodels.Userinfo.objects.filter(id=uid).first() 
 
    action = request.actions 
 
    user_list = rbacmodels.Userinfo.objects.all() 
 
    return render(request,"rbac_user.html",{"action":action,"user_list":user_list}) 

  

首先从request对象中获取我们在中间件函数中赋值的actions变量,然后渲染到前端

Django的Rbac介绍2详解编程语言

 我们在看下前端的html页面,我们只需要判断这次的用户对某张表是否有del、list、edit、add权限就可以了,因为这些信息我们都单独放在action中了

{#                 方式1#} 
                     {%  if "/user/del/(/d+)" in per_list %} 
                        <a href="/user/del/{{ user.id }}"><button type="button" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span>&nbsp删除</button></a> 
                     {% endif %} 
{#                    方式2#} 
                     {%  if "del" in request.actions %} 
                        <a href="/user/del/{{ user.id }}"><button type="button" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span>&nbsp删除</button></a> 
                     {% endif %} 

  

这里我们可以对比一下方式1和方式2的区别

Django的Rbac介绍2详解编程语言

 只需要判断是否有增删改查的权限就可以了,无需在判断表的名称

至此Djang的权限控制我们就做完了

—————————————————————————————————————————-

我们还有一个点可以优化一下,我们可以重新写一个类,这个类我们需要传递一个action进来,然后定义增删改查4个方法,每个方法都判断action中是否有对应的方法就可以了

class Per(object): 
    def __init__(self,actions): 
        self.actions = actions 
    def add(self): 
        return "add" in self.actions 
    def edit(self): 
        return "edit" in self.actions 
    def dele(self): 
        return "del" in self.actions 
    def list(self): 
        return "list" in self.actions 

  

所以我们在前端判断就更加简单了

先在视图函数中实例化一个对象

    Per_obj = Per(request.actions) 
 
    return render(request,"rbac_user.html",{"Per_obj":Per_obj}) 

  

然后在htmlz中调用这个实例变量的方法就可以了

 Django的Rbac介绍2详解编程语言

 是不是这样写就更加简单了

好了Django的Rbac我们就介绍到这里了,谢谢大家关注!

原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/20785.html

(0)
上一篇 2021年7月19日 23:44
下一篇 2021年7月19日 23:44

相关推荐

发表回复

登录后才能评论