1. 程式人生 > >Django的Rbac的介紹2

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個欄位

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這個變數的值

 

 

 

其實這裡和方法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變數,然後渲染到前端

 

 

 我們在看下前端的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的區別

 

 

 只需要判斷是否有增刪改查的許可權就可以了,無需在判斷表的名稱

 

至此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我們就介紹到這裡了,謝謝大家關注!