一、將rbac組件拷貝到項(xiàng)目中。注意:
<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>
INSTALLED_APPS = [ ... 'rbac.apps.RbacConfig' ... ] 二、將rbac/migrations目錄中的數(shù)據(jù)庫遷移記錄刪除(init.py不能刪除)三、業(yè)務(wù)系統(tǒng)中用戶表結(jié)構(gòu)的設(shè)計(jì)業(yè)務(wù)表結(jié)構(gòu)中的用戶表需要和rbac中的用戶表有繼承關(guān)系如:
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) # 去掉引號(hào)就把Role這個(gè)類的內(nèi)存地址也繼承過去了,這樣做數(shù)據(jù)庫遷移就不會(huì)報(bào)錯(cuò)了 def __str__(self): return self.name class Meta: # django以后再做數(shù)據(jù)庫遷移時(shí),不再為UserInfo類創(chuàng)建相關(guān)的表以及表結(jié)構(gòu)了 # 此類可以當(dāng)做"父類",被其他Model類繼承。里面的字段就自動(dòng)過度給繼承它的類了 abstract = True 注意:
from rbac.models import UserInfo as RbacUserInfo class Host(models.Model): """主機(jī)表""" hostname = models.CharField(verbose_name='主機(jī)名', 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='聯(lián)系方式', 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) 遷移數(shù)據(jù)庫./manage.py makemigrations ./manage.py migrate 四、將業(yè)務(wù)系統(tǒng)中的用戶表的路徑寫到配置文件settings.py
在權(quán)限組件的視圖函數(shù)中將用戶表改為新的,所有的UserInfo都要改成user_model_class rbac/views/menu.py ... from django.conf import settings from django.utils.module_loading import import_string ... ... def distribute_permissions(request): """ 權(quán)限分配 :param request: :return: """ user_id = request.GET.get('uid') # user_object = models.UserInfo.objects.filter(id=user_id).first() # 之前的用戶表,不要了 # 業(yè)務(wù)中的用戶表 user_model_class = import_string(settings.RBAC_USER_MODEL_CLASS) # 自動(dòng)根據(jù)字符串的形式,把這個(gè)類導(dǎo)入進(jìn)來 user_object = user_model_class.objects.filter(id=user_id).first() ... 五、業(yè)務(wù)邏輯開發(fā)1. 開發(fā)一個(gè)登陸功能2.將所有的路由都設(shè)置一個(gè)name,用來反向生成url以及粒度控制到按鈕級別的權(quán)限控制。如: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'), ] 六、權(quán)限信息的錄入在url中添加rbac的路由分發(fā)。注意:必須設(shè)置namesapce項(xiàng)目/urls.py ... from django.urls import path, re_path, include ... urlpatterns = [ ... path('rbac/', include(('rbac.urls', 'rbac'))), ... ] 注意:rbac中的用戶管理相關(guān)的URL配置要注釋掉或刪除掉 添加菜單、分配角色、錄入權(quán)限rbac提供的地址進(jìn)行操作 菜單列表 - http://127.0.0.1:8000/rbac/menu/list/ 角色列表 - http://127.0.0.1:8000/rbac/role/list/ 權(quán)限分配 - http://127.0.0.1:8000/rbac/distribute/permissions/ 1. 先添加一級菜單,然后批量錄入二級菜單和權(quán)限 2. 添加完菜單后創(chuàng)建角色 3. 最后記得分配權(quán)限,否則后面加上中間件后會(huì)提示無權(quán)限訪問 相關(guān)配置:自動(dòng)發(fā)現(xiàn)URL時(shí),排除的URL AUTO_DISCOVER_EXCLUDE = [ '/admin/', '/login/', '/logout/', '/index/', ] 注意:如果排除的URL中,如admin、login等用的是django2.0新出的path方法,那么正則匹配的之后需要寫成/admin.*,因?yàn)閜ath會(huì)在admin后面加一個(gè)斜杠(\)。/admin/配置的話就會(huì)在自動(dòng)發(fā)現(xiàn)URL中出現(xiàn)一推這樣的URL:/admin/ 七、編寫用戶登錄的邏輯【進(jìn)行權(quán)限的初始化】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': '用戶名或密碼錯(cuò)誤'}) # 用戶權(quán)限信息的初始化 init_permission(user_obj, request) return redirect(reverse('index')) 相關(guān)配置:權(quán)限和菜單的session key: PERMISSION_SESSION_KEY = 'permission_url_list_key' MENU_SESSION_KEY = 'permission_menu_key' 八、編寫一個(gè)首頁的邏輯def index(request): return render(request, 'index.html') 相關(guān)配置: # 需要登錄,但無需權(quán)限的URL NO_PERMISSION_LIST = [ '/logout/', '/index/', ] 在中間件新增無需權(quán)限校驗(yàn),但是需要登錄才能訪問的功能 ... url_record = [ {'title': '首頁', 'url': '#'} ] # 此處代碼進(jìn)行判斷:/logout/,/index/ 無需權(quán)限校驗(yàn),但是需要登錄才能訪問 for url in settings.NO_PERMISSION_LIST: if re.match(url, request.path_info): # 需要登錄,但無需權(quán)限校驗(yàn) request.current_selected_permission = 0 # 等于0就是沒有默認(rèn)選中,和菜單沒有關(guān)聯(lián)上,就不會(huì)做默認(rèn)展開 request.breadcrumb = url_record return None has_permission = False ... 九、通過中間件進(jìn)行權(quán)限的校驗(yàn)rbac/middlewares/rabc.py # 權(quán)限校驗(yàn) 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/.*'] 十、粒度到按鈕級別的控制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>手機(jī)</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 %} 總結(jié):目的是希望在任意系統(tǒng)中應(yīng)用權(quán)限系統(tǒng)
INSTALLED_APPS = [ ... 'host.apps.HostConfig', 'rbac.apps.RbacConfig' ... ] MIDDLEWARE = [ ... 'rbac.middlewares.rbac.RbacMiddleware', ... ] # 業(yè)務(wù)中的用戶表 RBAC_USER_MODEL_CLASS = 'host.models.UserInfo' # 權(quán)限在session中存儲(chǔ)的key PERMISSION_SESSION_KEY = 'permission_url_list_key' # 菜單在Session中存儲(chǔ)的key MENU_SESSION_KEY = 'permission_menu_key' # 白名單 WHITE_LIST = ['/login/', '/admin/.*'] # 自動(dòng)發(fā)現(xiàn)路由中URL時(shí),排除的URL AUTO_DISCOVER_EXCLUDE = [ '/admin.*', '/login.*', '/logout.*', '/index.*', ] # 需要登錄,但無需權(quán)限的URL NO_PERMISSION_LIST = [ '/logout/', '/index/', ]
|
|