1. 程式人生 > >django的Rbac介紹1

django的Rbac介紹1

1、django的許可權管理叫做RBAC

我們在百度上檢視RBAC的概念如下

基於角色的許可權訪問控制(Role-Based Access Control)作為傳統訪問控制(自主訪問,強制訪問)的有前景的代替受到廣泛的關注。在RBAC中,許可權與角色相關聯,使用者通過成為適當角色的成員而得到這些角色的許可權。這就極大地簡化了許可權的管理。在一個組織中,角色是為了完成各種工作而創造,使用者則依據它的責任和資格來被指派相應的角色,使用者可以很容易地從一個角色被指派到另一個角色。角色可依新的需求和系統的合併而賦予新的許可權,而許可權也可根據需要而從某角色中回收。角色與角色的關係可以建立起來以囊括更廣泛的客觀情況。

 

2、下面我們先來看下django的rbac該如何設計

首先我們要設計三張表,表1為使用者表,表2為角色表,表3為許可權表,使用者表關聯角色表,角色表關聯許可權表,使用者屬於某個角色,而某個角色可以包含一些許可權,同樣一個使用者可以屬於多個角色,而一個角色同樣可以包含多個許可權,下面我們看下我們的model中的設計

from django.db import models

# Create your models here.

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

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

class per(models.Model):
    title = models.CharField(max_length=64)
    url = models.CharField(max_length=128)

    def __str__(self):
        return self.title
    class Meta:
        verbose_name = "許可權表"

  

設計好表結構後,我們先往表中寫資料,我們先看使用者表中的資料

 

我們點開看下具體某個使用者的角色資訊

我們可以看到,使用者test1有2個角色,角色1是CEO,角色2是銷售角色

 

然後我們在看角色表

 

 我們在看下某個角色具體的許可權,我們這裡定義許可權就是操作庫的許可權,比如增刪改查四個許可權

 

 我們可以看到CEO有4個許可權,分別是增刪改查4個許可權

 

最後我們在看下許可權表,通過許可權表,我們就可以看到一共有4個許可權

 

我們看下具體的許可權的表內容,我們可以看到具體的許可權就是一條url

 

 從上面的資料庫的設計,我們可以知道,控制url的訪問就是控制權限

 

 3、最後我們進入具體的程式碼的邏輯控制

我們思路是這樣的,因為從上面我們可以看到,如果某個使用者沒有某個許可權,那麼我們就控制這個使用者是否能訪問這條url就可以了,那麼我們怎麼做呢?

思路1、可以寫在檢視函式中

思路2、可以寫在檢視函式的裝飾器中

思路3、可以寫在中介軟體中

我們可以考慮一下,哪種最好呢?當然是第三種最好,因為每個請求都會發一個request,如果這個使用者沒有這個方位這個url的許可權,那麼我們直接在中介軟體就把這個請求攔截就可以了,不需要讓這個請求在往後走,佔用我們的資源,您說對嗎?

那麼下面就看下具體的程式碼

使用者首先要登陸,那麼登陸後,我們就需要把使用者資訊儲存到session中,同樣,我們也需要從資料庫中獲取我這個使用者的許可權資訊,然後儲存到session中,以後我們就可以從session拿到我這次訪問的使用者和我這個使用者所擁有的許可權,以後我們中介軟體函式就從session中獲取這次訪問的使用者資訊

檢視函式中的程式碼如下

def login(request):
    if request.method == "GET":
        return render(request, "rbac_login.html")
    else:
        name = request.POST.get("name")
        pwd = request.POST.get("pwd")

        if rbacmodels.Userinfo.objects.filter(username=name,uerpwd=pwd).exists():
            userobj = rbacmodels.Userinfo.objects.get(username=name)

            request.session["userid"] = userobj.id

            # print(userobj.roles.all())
            obj = userobj.roles.all().values_list("pers__url").distinct()
            per_list = []
            for i in obj:
                per_list.append(i[0])
            request.session["per_list"] = per_list
            print(per_list)
            # request.session.flush()
            # print(dir(request.session))
            # print("=" * 120)
            return redirect("/user/")
        else:
            return render(request, "rbac_login.html")

  

 

下面我們在看下中介軟體函式是怎麼實現的

我們首先要搞一個白名單,如果url在這個白名單裡,則可以直接訪問,不用走後面的控制邏輯,因為比如login這類的url,你必須要放通他,如果你連login函式也攔截了,那麼可以都無法登陸了

 

其次我們還要搞一個判斷使用者是否登陸的判斷,如果客戶沒有登陸,則讓他返回到登陸介面

 

最後,我們在寫許可權的控制邏輯,判斷當前訪問的url是否在許可權列表中,如果在則通過,如果不在,則直接retrun回去,就達到了許可權控制的需求了

from django.utils.deprecation import MiddlewareMixin
import re
from django.shortcuts import HttpResponse
from django.shortcuts import redirect
from django.shortcuts import reverse

class My_rbac_mid(MiddlewareMixin):

    def process_request(self,request):
        current_path = request.path_info


        # 校驗白名單

        white_list = ["/login/","/admin/.*"]
        for wh in white_list:
            wh = "^" + wh + "$"
            res = re.match(wh,current_path)
            if res:
                return None

        # 校驗登陸
        if request.session.get("userid"):
            pass
        else:
            return redirect("/login/")


        # 校驗許可權
        per_list = request.session.get("per_list",[])
        flag = False
        if per_list:
            for per in per_list:
                if flag == False:
                    obj = "^" + per + "$"
                    res = re.match(obj,current_path)
                    if res:
                        flag = True
                        break
                    else:
                        continue
        if flag == False:
            return HttpResponse("無許可權訪問")

  

4、最後我們看下html程式碼是如何渲染的,我們的目的是如果該使用者沒有這個許可權,則連按鈕都不讓他看到

{% extends 'rbac_base.html' %}


{% block con %}

    <h4>使用者列表</h4>

    {% if "/user/add/" in per_list %}
        <a href="/user/add/" class="btn btn-primary">新增使用者</a>
    {% endif %}


    <table class="table table-bordered table-striped">
        <thead>
              <tr>
                   <th>序號</th>
                   <th>姓名</th>
                   <th>角色</th>
                   <th>操作</th>
              </tr>
        </thead>
       <tbody>
            {% for user in user_list %}
            <tr>
                 <td>{{ forloop.counter }}</td>
                 <td>{{ user.username }}</td>
                 <td>
                     {% for role in user.roles.all %}
                        {% if forloop.last %}
                            {{ role.title }}
                         {% else %}
                            {{ role.title }}|
                         {% endif %}
                     {% endfor %}

                 </td>

                 <td>
                     {%  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 %}

                    {%  if "/user/edit/(\d+)" in per_list %}
                        <a href="/user/edit/{{ user.id }}"><button type="button" class="btn btn-success"><span class="glyphicon glyphicon-pencil"></span>&nbsp編輯</button></a>
                    {% endif %}
                 </td>
            </tr>
            {% endfor %}

       </tbody>
    </table>


{% endblock %}

  

我將邏輯控制的地方截圖出來,大家重點看下

如果有增加許可權,則顯示增加按鈕

 

 如果有刪除許可權,則顯示刪除按鈕

 

 如果有 編輯許可權,則顯示i編輯按鈕