權限組件(15):rbac的使用文檔和在業務中的應用

這裏用主機管理系統當作示例。css

 

1、將rbac組件拷貝到項目中。

注意:

  1.  rbac本身的靜態文件、layout.html(被繼承的模板)、bootstrap、fontsize、公共的css、jquery、layout裏用到的圖片也要拷貝進來 
  2. 在settings.py註冊rbac: 
  3. 二級菜單和麪包屑導航須要先註釋掉
  4. 在settings中將LANGUAGE_CODE = 'en-us'改成LANGUAGE_CODE = 'zh-hans'
在layout.html裏註釋掉二級菜單和麪包屑導航

<div class="pg-body">
    <div class="left-menu">
        <div class="menu-body">
{#            {% multi_menu request %}#}
        </div>
    </div>
    <div class="right-body">
{#        {% breadcrumb request %}#}
        {% block content %} {% endblock %}
    </div>
</div>

在settings.py裏註冊rbac

INSTALLED_APPS = [
    ...
    'rbac.apps.RbacConfig'
    ...
]
 

2、將rbac/migrations目錄中的數據庫遷移記錄刪除(init.py不能刪除)

 

3、業務系統中用戶表結構的設計

業務表結構中的用戶表須要和rbac中的用戶表有繼承關係如:html

  • rbac/models.py
class UserInfo(models.Model):
    """
    用戶表
    """
    name = models.CharField(verbose_name='用戶名', max_length=32)
    password = models.CharField(verbose_name='密碼', max_length=64)
    email = models.CharField(verbose_name='郵箱', max_length=32)
    roles = models.ManyToManyField(verbose_name='擁有的全部角色', to=Role, blank=True)
    # 去掉引號就把Role這個類的內存地址也繼承過去了,這樣作數據庫遷移就不會報錯了

    def __str__(self):
        return self.name

    class Meta:
        # django之後再作數據庫遷移時,再也不爲UserInfo類建立相關的表以及表結構了
        # 此類能夠當作"父類",被其餘Model類繼承。裏面的字段就自動過分給繼承它的類了
        abstract = True

 

注意:jquery

  1. 改爲abstract後就不能在admin裏註冊了
  2. 多對多關聯Role的時候不能加引號
  • 業務/models.py
from rbac.models import UserInfo as RbacUserInfo

class Host(models.Model):

    """主機表"""
    hostname = models.CharField(verbose_name='主機名', max_length=32)
    ip = models.GenericIPAddressField(verbose_name='IP', protocol='both')
    department = models.ForeignKey(verbose_name='歸屬部門', to='Department', on_delete=models.CASCADE)

    def __str__(self):
        return self.hostname
        
class UserInfo(RbacUserInfo):
    """用戶表"""

    phone = models.CharField(verbose_name='聯繫方式', max_length=32)
    T1 = 1
    T2 = 2
    T3 = 3
    level_choices = (
        (T1, 'T1'),
        (T2, 'T2'),
        (T3, 'T3')
    )
    level = models.IntegerField(verbose_name='級別', choices=level_choices)
    department = models.ForeignKey(verbose_name='部門', to='Department', on_delete=models.CASCADE)

 

遷移數據庫

./manage.py makemigrations
./manage.py migrate

 

4、將業務系統中的用戶表的路徑寫到配置文件

settings.pygit

# 業務中的用戶表
RBAC_USER_MODEL_CLASS = 'host.models.UserInfo' # 用於在rbac分配權限時,讀取業務表中的用戶信息。

host換成你的業務appgithub

在權限組件的視圖函數中將用戶表改成新的,全部的UserInfo都要改爲user_model_class數據庫

rbac/views/menu.pydjango

...
from django.conf import settings
from django.utils.module_loading import import_string
...


...
def distribute_permissions(request):
    """
    權限分配
    :param request:
    :return:
    """

    user_id = request.GET.get('uid')
    
    # user_object = models.UserInfo.objects.filter(id=user_id).first()  # 以前的用戶表,不要了

    # 業務中的用戶表
    user_model_class = import_string(settings.RBAC_USER_MODEL_CLASS) # 自動根據字符串的形式,把這個類導入進來

    user_object = user_model_class.objects.filter(id=user_id).first()
...

 

 5、業務邏輯開發

1. 開發一個登錄功能

2.將全部的路由都設置一個name,用來反向生成url以及粒度控制到按鈕級別的權限控制。如:

from django.contrib import admin
from django.urls import path, re_path

from host.views import account
from host.views import user
from host.views import host

urlpatterns = [
    re_path(r'^admin/', admin.site.urls),

    re_path(r'^login/$', account.login, name='login'),
    re_path(r'^logout/$', account.logout, name='logout'),
    re_path(r'^index/$', account.index, name='index'),

    re_path(r'^user/list/$', user.user_list, name='user_list'),
    re_path(r'^user/add/$', user.user_add, name='user_add'),
    re_path(r'^user/edit/(?P<pk>\d+)/$', user.user_edit, name='user_edit'),
    re_path(r'^user/delete/(?P<pk>\d+)/$', user.user_delete, name='user_delete'),
    re_path(r'^user/reset/pwd/(?P<pk>\d+)/$', user.user_reset_pwd, name='user_reset_pwd'),

    re_path(r'^host/list/$', host.host_list, name='host_list'),
    re_path(r'^host/add/$', host.host_add, name='host_add'),
    re_path(r'^host/edit/(?P<pk>\d+)/$', host.host_edit, name='host_edit'),
    re_path(r'^host/delete/(?P<pk>\d+)/$', host.host_delete, name='host_delete'),

]

 

6、權限信息的錄入

在url中添加rbac的路由分發。注意:必須設置namesapce

項目/urls.pybootstrap

...
from django.urls import path, re_path, include
...

urlpatterns = [
 ...
 path('rbac/', include(('rbac.urls', 'rbac'))),
 ...
 ]

 

注意:rbac中的用戶管理相關的URL配置要註釋掉或刪除掉session

添加菜單、分配角色、錄入權限

rbac提供的地址進行操做app

菜單列表 - http://127.0.0.1:8000/rbac/menu/list/
角色列表 - http://127.0.0.1:8000/rbac/role/list/
權限分配 - http://127.0.0.1:8000/rbac/distribute/permissions/

1. 先添加一級菜單,而後批量錄入二級菜單和權限

2. 添加完菜單後建立角色

3. 最後記得分配權限,不然後面加上中間件後會提示無權限訪問

 

相關配置:自動發現URL時,排除的URL

AUTO_DISCOVER_EXCLUDE = [
    '/admin/',
    '/login/',
    '/logout/',
    '/index/',
]

 

注意:若是排除的URL中,如admin、login等用的是django2.0新出的path方法,那麼正則匹配的以後須要寫成/admin.*,由於path會在admin後面加一個斜槓(\)。/admin/配置的話就會在自動發現URL中出現一推這樣的URL:/admin/

7、編寫用戶登陸的邏輯【進行權限的初始化】

def login(request):
    """
    登陸
    :param request:
    :return:
    """
    if request.method == 'GET':
        return render(request, 'login.html')
    user = request.POST.get('username')
    pwd = request.POST.get('password')

    user_obj = models.UserInfo.objects.filter(name=user, password=pwd).first()

    if not user_obj:
        return render(request, 'login.html', {'error': '用戶名或密碼錯誤'})

    # 用戶權限信息的初始化
    init_permission(user_obj, request)

    return redirect(reverse('index'))

 

相關配置:權限和菜單的session key:

PERMISSION_SESSION_KEY = 'permission_url_list_key'
MENU_SESSION_KEY = 'permission_menu_key'

 

8、編寫一個首頁的邏輯

def index(request):
    return render(request, 'index.html')

 

相關配置:

# 須要登陸,但無需權限的URL
NO_PERMISSION_LIST = [
    '/logout/',
    '/index/',
]

 

在中間件新增無需權限校驗,可是須要登陸才能訪問的功能

 ...
 url_record = [
            {'title': '首頁', 'url': '#'}
        ]

        # 此處代碼進行判斷:/logout/,/index/  無需權限校驗,可是須要登陸才能訪問
        for url in settings.NO_PERMISSION_LIST:
            if re.match(url, request.path_info):
                # 須要登陸,但無需權限校驗
                request.current_selected_permission = 0  # 等於0就是沒有默認選中,和菜單沒有關聯上,就不會作默認展開
                request.breadcrumb = url_record
                return None

        has_permission = False
...

 

9、經過中間件進行權限的校驗

rbac/middlewares/rabc.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.middlewares.rbac.RbacMiddleware',
]

 

白名單

# 白名單,無需登陸就能夠訪問
WHITE_LIST = ['/login/', '/admin/.*']

 

10、粒度到按鈕級別的控制

host/templates/user_list.html

{% extends 'layout.html' %}
{% load rbac %}


{% block content %}

    <h1>用戶列表</h1>
    <div class="custom-container">
        <div class="btn-group" style="margin: 5px 0">
            {% if request|has_permission:'user_add' %}  <!-- 控制增長按鈕 -->
                <a class="btn btn-default" href="{% memory_url request 'user_add' %}">
                    <i class="fa fa-plus-square" aria-hidden="true"></i> 添加用戶
                </a>
            {% endif %}
        </div>

        <table class="table table-bordered table-hover">
            <thead>
            <tr>
                <th>用戶名</th>
                <th>郵箱</th>
                <th>級別</th>
                <th>部門</th>
                <th>手機</th>
                {% if request|has_permission:'user_reset_pwd' %}  <!-- 控制重置密碼按鈕 -->
                    <th>重置密碼</th>
                {% endif %}
                {% if request|has_permission:'user_edit' or 'user_delete' %}
                    <th>操做</th>
                {% endif %}
            </tr>
            </thead>
            <tbody>
            {% for row in user_queryset %}
                <tr>
                    <td>{{ row.name }}</td>
                    <td>{{ row.email }}</td>
                    <td>{{ row.get_level_display }}</td>
                    <td>{{ row.department.title }}</td>
                    <td>{{ row.phone }}</td>

                    {% if request|has_permission:'user_reset_pwd' %}  
                        <td>
                            <a href="{% memory_url request 'user_reset_pwd' pk=row.id %}">重置密碼</a>
                        </td>
                    {% endif %}

                    {% if request|has_permission:'user_edit' or 'user_delete' %}  <!-- 控制編輯和刪除按鈕 -->
                        <td>
                            {% if request|has_permission:'user_edit' %}
                                <a style="color: #333333; font-size:18px"
                                   href="{% memory_url request 'user_edit' pk=row.id %}">
                                    <i class="fa fa-edit" aria-hidden="true"></i></a>
                            {% endif %}

                            {% if request|has_permission:'user_delete' %}
                                <a style="color: red; font-size:18px"
                                   href="{% memory_url request 'user_delete' pk=row.id %}">
                                    <i class="fa fa-trash-o" aria-hidden="true"></i></a>
                            {% endif %}

                        </td>
                    {% endif %}

                </tr>
            {% endfor %}
            </tbody>
        </table>

    </div>

{% endblock content %}

 

總結:目的是但願在任意系統中應用權限系統

  1. 用戶登陸 + 用戶首頁 + 用戶註銷 + 業務邏輯

  2. 業務邏輯開發。注意,開發時要靈活的去設計layout.html中的兩個inclusion_tag

  1. 權限信息的錄入

  2. 配置文件

INSTALLED_APPS = [
    ...
    'host.apps.HostConfig',
    'rbac.apps.RbacConfig'
    ...
]

MIDDLEWARE = [
    ...
    'rbac.middlewares.rbac.RbacMiddleware',
    ...
]

# 業務中的用戶表
RBAC_USER_MODEL_CLASS = 'host.models.UserInfo'

# 權限在session中存儲的key
PERMISSION_SESSION_KEY = 'permission_url_list_key'

# 菜單在Session中存儲的key
MENU_SESSION_KEY = 'permission_menu_key'

# 白名單
WHITE_LIST = ['/login/', '/admin/.*']

# 自動發現路由中URL時,排除的URL
AUTO_DISCOVER_EXCLUDE = [
    '/admin.*',
    '/login.*',
    '/logout.*',
    '/index.*',
]

# 須要登陸,但無需權限的URL
NO_PERMISSION_LIST = [
    '/logout/',
    '/index/',
]
  1. 粒度到按鈕級別的控制
相關文章
相關標籤/搜索