用户权限认证组件包括权限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。