RBAC權限系統實現步驟-初版


一、創建並注冊APP

1. 創建App: python mange.py startapp rbac
2. 注冊APP:setting.py  
    INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'web.apps.WebConfig',
    'rbac.apps.RbacConfig'
    ]

 

二、設計表結構

from django.db import models
# Create your models here.
"""
RBAC涉及到5張表
    1. 用戶表  (用戶和角色是多對多的關系)
    2. 角色表  (角色和權限是多對多的關系)
    3. 權限表  
    4. 用戶-角色表
    5. 角色-權限表
"""


class UserInfo(models.Model):
    """
    用戶表
    roles 字段: 用戶和角色多對多字段,這個字段可以寫在用戶表或者角色表中,主要看場景是根據角色找用戶還是根據用戶找角色,
                在這個場景中,我們根據用戶找角色多,所以我們把ManyToManyField字段寫在用戶表中
        null = True : 允許為空
        blank = True: 在django Admin后台允許為空
    """
    username = models.CharField(max_length=32, verbose_name="用戶名")
    password = models.CharField(max_length=64, verbose_name="密碼")
    roles = models.ManyToManyField(to="Role", null=True, blank=True, verbose_name="用戶角色")

    def __str__(self):
        """
        在Django Admin中顯示數據名稱
        :return:
        """
        return self.username

    class Meta:
        """
        在Django Admin中顯示中文表名
        """
        verbose_name = "用戶表"
        verbose_name_plural = verbose_name


class Role(models.Model):
    """
    角色權限表
    Permissions: 角色和權限URL是多對多的關系,在這個場景中我們使用角色查找URL,所以我們把ManyToManyField寫在角色表中
    """
    name = models.CharField(max_length=36, verbose_name="角色名稱")
    Permissions = models.ManyToManyField(to="Permission", verbose_name="權限URL")

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "角色表"
        verbose_name_plural = verbose_name


class Permission(models.Model):
    """
    權限表
    保存需要控制的URL
    """
    name = models.CharField(max_length=16, verbose_name="UR名稱")
    url = models.CharField(max_length=255, verbose_name="URL路徑")
    is_menus = models.BooleanField(default=False, verbose_name="是否可作為菜單?")
    icon = models.CharField(max_length=255, verbose_name="菜單圖標", null=True, blank=True)

    def __str__(self):
        return self.url

    class Meta:
        verbose_name = "權限表"
        verbose_name_plural = verbose_name

 

三、創建表結構

python manage.py makemigrations
python manage.py migrate

 

四、使用Django Admin創建初始數據

1. python manage.py createsuperuser
2. 配置Django 后台中文(settings.py)
    LANGUAGE_CODE = 'zh-hans'
3. 注冊表到Admin中(admin.py)
    from django.contrib import admin
    from rbac import models

    # Register your models here.

    admin.site.register(models.UserInfo)
    admin.site.register(models.Role)


    # 自定義一個權限的管理類
    class PermissionAdmin(admin.ModelAdmin):
        # 告訴Django admin在頁面上展示我這張表的哪些字段
        list_display = ["name", "url", "is_menus", "icon"]
        # 在列表頁面支持直接修改的字段
        list_editable = ["url", "is_menus", "icon"]


    admin.site.register(models.Permission, PermissionAdmin)
4. 錄入基礎數據

 

五、寫登錄頁面

#!/usr/bin/env python3
from django.shortcuts import render, redirect
from rbac import models
from rbac.services import permission


def login(request):
    """
    用戶登錄頁面
        1. Get請求
            1. 返回登錄頁面
        2. Post請求
            1. 拿到頁面通過post傳過來的用戶名和者密碼
            2. 使用orm進行過濾查找
                1. 如果能找到值,則說明登錄成功
                    1. 登錄成功以后調用rbac函數初始化
                    2. 初始化的主要功能是獲取用戶的權限和菜單保存到session中
                    3. 跳轉到客戶列表頁面
                2. 登錄失敗,返回錯誤信息給頁面展示
    :param request: 
    :return: 
    """
    msg = {"msg": ""}
    if request.method == "POST":
        username = request.POST.get("username")
        password = request.POST.get("password")
        user_obj = models.UserInfo.objects.filter(username=username, password=password).first()
        if user_obj:
            permission.init_permission(request, user_obj)
            return redirect("/customer/list/")
        else:
            msg["msg"] = "用戶名或者密碼錯誤!"

    return render(request, "login.html", locals())

 

六、寫初始化函數(init_permission)

函數功能:根據登錄的用戶對象取到對象的權限和菜單保存到session中
#!/usr/bin/env python3
"""
用戶登錄成功以后,獲取用戶的的權限進行
"""
from django.conf import settings


def init_permission(request, user_obj):
    """
    初始化rbac
        1. 根據用戶對象,取到用戶對應的角色,根據角色在取到對應的權限。最后distinct做一個去重處理
        2. permission_list 定義一個用來存儲用戶權限的列表
        3. menus_list 定義一個用來存儲用戶菜單的列表
        4. 循環ret,添加權限和菜單到對應的列表
        5. 保存權限列表和菜單列表到session中
        備注:使用settings來存session的key方便在其他模塊中調用
    :param request: 用戶請求對象
    :param user_obj: 用戶orm對象
    :return:
    """
    ret = user_obj.roles.all().values(
        "Permissions__name",
        "Permissions__url",
        "Permissions__is_menus",
        "Permissions__icon"
    ).distinct()

    permission_list = []
    menus_list = []
    
    for item in ret:
        permission_list.append({"Permissions__url": item["Permissions__url"]})  # 添加到權限列表
        if item["Permissions__is_menus"]:  # 如果當前循環的權限可以作為菜單展示
            menus_list.append({  # 把當前權限的信息添加到菜單列表
                "name": item["Permissions__name"],
                "icon": item["Permissions__icon"],
                "url": item["Permissions__url"]
            })
    request.session[settings.PERMISSION_SESSION_KEY] = permission_list
    request.session[settings.MENU_SESSION_KEY] = menus_list

 

七、在登錄視圖中調用init_permission

#!/usr/bin/env python3
from django.shortcuts import render, redirect
from rbac import models
from rbac.services import permission


def login(request):
    """
    用戶登錄頁面
        1. Get請求
            1. 返回登錄頁面
        2. Post請求
            1. 拿到頁面通過post傳過來的用戶名和者密碼
            2. 使用orm進行過濾查找
                1. 如果能找到值,則說明登錄成功
                    1. 登錄成功以后調用rbac函數初始化
                    2. 初始化的主要功能是獲取用戶的權限和菜單保存到session中
                    3. 跳轉到客戶列表頁面
                2. 登錄失敗,返回錯誤信息給頁面展示
    :param request: 
    :return: 
    """
    msg = {"msg": ""}
    if request.method == "POST":
        username = request.POST.get("username")
        password = request.POST.get("password")
        user_obj = models.UserInfo.objects.filter(username=username, password=password).first()
        if user_obj:
            permission.init_permission(request, user_obj)
            return redirect("/customer/list/")
        else:
            msg["msg"] = "用戶名或者密碼錯誤!"

    return render(request, "login.html", locals())

 

八、自定義中間件

1. 在rbac APP下創建middleware中間庫目錄
2. 創建中間件rbac.py
    """
    自定義RBAC中間件
    功能描述:
        根據用戶角色實現權限控制
    """
    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import render, redirect, HttpResponse
    import re
    from django.conf import settings


    class RBACMiddleware(MiddlewareMixin):
        def process_request(self, request):
            """
            自定義中間件
            1. 中間件的描述
                1. 執行時間
                    在執行視圖函數之前執行
                2. 執行順序
                    按照注冊的順序執行
                3. 參數和返回值
                    1. request參數和視圖函數中是同一個對象
                    2. 返回值:
                        1. 返回None:請求繼續往后執行
                        2. 返回響應對象:請求就結束了,要返回響應了
            2. 取到用戶的url
                1. 循環白名單
                2. 判斷用戶當前訪問的URL是否在白名單中
                3. 如果在白名單中則返回None代碼繼續往后執行
            3. 取到用戶的訪問權限
                1. 如果沒有取到登錄時存的session,則說明用戶沒有登錄,跳轉到登錄頁面
            :param request:
            :return:
            """
            url = request.path_info

            for i in settings.PERMISSION_WHITE_URL:
                ret = "^{}$".format(i)
                if re.match(ret, url):
                    return None

            user_url = request.session.get(settings.PERMISSION_SESSION_KEY)
            if not user_url:
                return redirect("/login/")

            for i in user_url:
                ret = "^{}$".format(i["Permissions__url"])
                if re.match(ret, url):
                    return None
                else:
                    return HttpResponse("沒有權限方法")

3. 注冊中間件settings.py
    MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'rbac.middleware.rbac.RBACMiddleware',
    ]
    
4. 權限控制已經完成

 

九、開始配置菜單

方法1:
    直接在菜單html修改菜單html為:
    {% for menu in request.session.menu_list %}
        <a href="{{ menu.url }}" class="active">
        <span class="icon-wrap"><i class="fa {{ menu.icon }}"></i></span> {{ menu.name }}</a>
    {% endfor %}
方法2:
    使用模版語言的filter
    1. 修改菜單html
        {% load view %}
        {% show_menu request %}
    2. 創建app/templatetags/view.py
        from django import template
        from django.conf import settings

        register = template.Library()


        @register.inclusion_tag(filename="my_menu.html")
        def show_menu(request):
            menu_list = request.session.get(settings.MENU_SESSION_KEY)
            return {"menu_list": menu_list}
    3. 創建app/templates/my_menu.html
        <div class="static-menu">
            {% for menu in menu_list %}
                <a href="{{ menu.url }}" class="active">
                    <span class="icon-wrap"><i class="fa {{ menu.icon }}"></i></span> {{ menu.name }}</a>
            {% endfor %}
        </div>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM