用戶權限認證組件包括權限model類和中間件類python
model類介紹
Permission
權限類git
權限基本信息包括title:權限名稱 url:權限具體urlgithub
Role
角色類數據庫
角色類包括title:角色名稱 permission:角色的權限django
權限和角色多對多關係session
用戶類須要對Role類設置多對多映射app
Whitelist
白名單類函數
白名單包括title:權限名稱 url:權限具體urlurl
白名單內存放的是系統放行不進行權限校驗的urlspa
NeedLogin
登陸驗證包括title:url標題 url:具體url
登陸驗證表存放的是須要登陸才能進行操做或權限校驗的url,若是沒有登陸則會重定向到登陸頁面
models.py
from django.db import models class Permission(models.Model): ''' 權限基本信息包括title:權限名稱 url:權限具體url ''' title = models.CharField(max_length=32, verbose_name='權限名稱') url = models.CharField(max_length=200, verbose_name='url') def __str__(self): return self.title class Meta: verbose_name = '權限' verbose_name_plural = verbose_name class Role(models.Model): ''' 角色類包括title:角色名稱 permission:角色的權限 權限和角色多對多關係 用戶類須要對Role類設置多對多映射 ''' title = models.CharField(max_length=32, verbose_name='角色名稱') permission = models.ManyToManyField(Permission, verbose_name='權限') def __str__(self): return self.title class Meta: verbose_name = '角色' verbose_name_plural = verbose_name class Whitelist(models.Model): ''' 白名單包括title:權限名稱 url:權限具體url 白名單內存放的是系統放行不進行權限校驗的url ''' title = models.CharField(max_length=32, verbose_name='權限名稱') url = models.CharField(max_length=200, verbose_name='url') def __str__(self): return self.title class Meta: verbose_name = '白名單' verbose_name_plural = verbose_name class NeedLogin(models.Model): ''' 登陸驗證包括title:url標題 url:具體url 登陸驗證表存放的是須要登陸才能進行操做或權限校驗的url,若是沒有登陸則會重定向到登陸頁面 ''' title = models.CharField(max_length=32, verbose_name='url標題') url = models.CharField(max_length=200, verbose_name='url') def __str__(self): return self.title class Meta: verbose_name = '登陸驗證表' verbose_name_plural = verbose_name
中間件類介紹
VerifyPermissions
權限認證中間件實現了process_request和process_view方法。中間件在初始化時會從數據庫更新白名單列表和須要登陸認證的url列表,這個中間件實現了用戶訪問權限認證,登陸認證功能。
verify.py
from django.shortcuts import render, HttpResponse, redirect from permission.models import Whitelist, NeedLogin from django.utils.deprecation import MiddlewareMixin import re from django.conf import settings class VerifyPermissions(MiddlewareMixin): # 只在中間件加載時執行一次 # 獲取白名單列表 whitelist = Whitelist.objects.values('url').all() # 獲取須要登陸的url列表 needLogin_list = NeedLogin.objects.values('url').all() def process_request(self, request): ''' 對用戶的請求和登陸驗證的url進行匹配,若是匹配成功且用戶沒有登陸,則重定向到登陸頁面 須要在settings.py配置LOGIN_URL :param request: :return: ''' current_url = request.path # 從session中取用戶登陸的數據,在登陸視圖函數內,登陸成功須要在session中存儲登陸用戶信息,這裏使用user做爲登陸用戶信息的key user = request.session.get("user", "") # 校驗是不是登陸驗證表的內容,若是是且已登陸則放行,若是不是登陸驗證表的內容則會放行到urls.py,若是未登陸則重定向到登陸頁面 for url in self.needLogin_list: ret = re.fullmatch(url['url'], current_url) if ret: if user: return else: return redirect(settings.LOGIN_URL) def process_view(self, request, view_func, view_args, view_kwargs): ''' 根據中間中process_*方法執行的順序,process_view方法是在請求到達urls.py以後在執行view.py視圖函數以前執行的 使用process_view方法不使用process_request是由於若是用戶輸入了找不到的路徑,能夠先提示404,不會先提示權限問題 ''' current_url = request.path # 校驗是不是白名單的內容,若是是則放行 for url in self.whitelist: ret = re.fullmatch(url['url'], current_url) if ret: return # 從session中獲取權限列表 permissions_list = request.session.get('permissions_list', []) # 校驗是不是權限內的內容,若是不是提示權限不夠 for url in permissions_list: ret = re.fullmatch(url['url'], current_url) if ret: return else: # 可設置自定義頁面 return HttpResponse('權限不夠')
管理員經過django的admin更新白名單或者登陸驗證表時須要及時更新中間件中的白名單列表和登陸驗證url列表,避免重啓項目。這裏使用重寫admin.ModelAdmin的save_model和delete_model方法。
admin.py
from django.contrib import admin from permission.models import * from permission.verify import VerifyPermissions class WhitelistAdmin(admin.ModelAdmin): ''' 因爲只在中間件加載第一次時加載白名單,因此對白名單內容作修改時,應對中間件中內容更新 ''' def save_model(self, request, obj, form, change): obj.save() VerifyPermissions.whitelist = Whitelist.objects.values('url').all() def delete_model(self, request, obj): obj.delete() VerifyPermissions.whitelist = Whitelist.objects.values('url').all() class NeedLoginAdmin(admin.ModelAdmin): ''' 因爲只在中間件加載第一次時加載登陸驗證表,因此對登陸驗證表內容作修改時,應對中間件中內容更新 ''' def save_model(self, request, obj, form, change): obj.save() VerifyPermissions.needLogin_list = NeedLogin.objects.values('url').all() def delete_model(self, request, obj): obj.delete() VerifyPermissions.needLogin_list = NeedLogin.objects.values('url').all() admin.site.register(Permission) admin.site.register(Role) admin.site.register(Whitelist, WhitelistAdmin) admin.site.register(NeedLogin, NeedLoginAdmin)
使用說明:
組件Github地址:https://github.com/WPN0837/RBAC
PS:Github上是組件的一個使用示例
只須要把permission下的內容複製到須要權限認證的項目中便可使用
在使用這個組件的項目中註冊這個組件,在settings.py的INSTALLED_APPS添加'permission.apps.PermissionConfig',例如:
INSTALLED_APPS = [ ''' 'permission.apps.PermissionConfig', ]
添加中間件,在settings.py的MIDDLEWARE添加'permission.verify.VerifyPermissions',例如:
MIDDLEWARE = [ ''' 'permission.verify.VerifyPermissions', ]
PS:VerifyPermissions必定要寫在SessionMiddleware後面,由於VerifyPermissions使用到了session
使用須要注意的地方:
在項目定義User類的地方須要先引入permission.models下的Role類
例如from permission.models import Role
再在User綁定User類與Role類多對多映射關係
具體如:
class UserInfo(models.Model): username = models.CharField(max_length=20) pwd = models.CharField(max_length=20) # 綁定用戶與角色多對多映射關係 role = models.ManyToManyField(Role, verbose_name='角色') def __str__(self): return self.username
在配置文件settings.py文件中須要配置登陸的URL,要與urls.py文件中相同,例如:
# settings.py # 也可以使用登陸url的別名 LOGIN_URL = "/login/"
# urls.py urlpatterns = [ path('admin/', admin.site.urls), path('', index), # 登陸的url,也可使用別名 path('login/', login), ]
在用戶登陸視圖函數裏,若是登陸成功應當把用戶信息和用戶權限信息保存到用戶的session中,例如:
def login(request): if request.method == 'GET': name = request.GET.get('name', '') pwd = request.GET.get('pwd', '') u = UserInfo.objects.filter(username=name, pwd=pwd).first() if u: # 保存用戶信息 request.session['user'] = name # 保存用戶權限信息 request.session['permissions_list'] = list( Permission.objects.filter(role__in=u.role.all()).values('url').all()) return HttpResponse('登陸成功') else: return HttpResponse('登陸失敗')
具體保存到session裏的數據的key由中間件類VerifyPermissions的process_request(使用了user)和process_view(使用了permissions_list)方法裏使用到session的地方決定,可本身修改。
在添加完組件後,首先遷移數據庫文件,而後把中間件VerifyPermissions註釋掉,再進入django admin管理後臺,在白名單中添加/admin/.*這個url,權限名稱能夠設置成admin或者其餘的,再取消中間件VerifyPermissions的註釋,由於沒有admin後臺的url添加進白名單,會提示沒有權限訪問/admin/開頭的url。