rbac:基于角色的权限访问控制(Role-Based Access Control)。
rbac的主要流程:给每个角色赋予不同的权限,是这个角色的员工都有这个角色的所有权限。一个角色可以有多个人员担任,一个员工可以担任多个角色(比如部门经理、业务员等)。当员工成功登陆系统时,系统需要获取这个员工的多有权限,并放到一个列表里面。然后员工在访问每个权限url时,系统需要进行判断该员工有没有这个权限进行这项操作。如何判断?就是循环这个员工的所有权限,看有没有对应的权限。这里用到了re模块里面的match方法。
如下代码:
# 需要先登陆,拿到该员工的权限列表并去重
def login(request): if request.method=="GET": return render(request,"login.html") else: user=request.POST.get("user") pwd=request.POST.get("pwd") user=UserInfo.objects.filter(name=user,pwd=pwd).first() if user: # 验证成功之后做什么? request.session["user_id"]=user.pk # 设置session # 当前登录用户的所有权限, distinct()是去掉重复的权限 permission_info=user.roles.all().values("permissions__url","permissions__title").distinct() temp=[] # 该员工的全部权限url列表 for i in permission_info: temp.append(i["permissions__url"]) request.session["permission_list"]=temp # {"user_id":1,"permission_list":['/users/','/orders/']} return HttpResponse("登录成功!") else: return redirect("/login/")
登陆成功之后,判断查看用户操作权限
from django.shortcuts import HttpResponse def users(request): # //users/ current_path = request.path_info # 拿到访问的路径 permission_list = request.session.get("permission_list") # 取session,从session表里面取到这个员工的所有权限 ['/order/', '/users/']
if not permission_list: # 用户没有登陆,取不到权限列表
return HttpResponse("login.html") # /users/edit/3 为什么要用正则,因为/users/edit/3 与/users/edit/(/d+)不能直接匹配 import re flag = False # 加上标志位 for permission_url in permission_list: ret = re.match(permission_url, current_path) # 用正则去匹配具体的路径,成功则返回对象, 否则返回None if ret: # 如果返回对象 flag = True break if not flag: return HttpResponse("没有访问权限") return HttpResponse("用户列表") # 有权限
接下来通过中间件来实现这个功能
再创建一个应用名字叫做rbac(当然也可以放到同一个应用里面),这个应用里面创建一个包service,包里创建一个名字为permission_li.py的文件。
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import redirect,HttpResponse,render class M1(MiddlewareMixin): def process_request(self,request): # //users/ current_path = request.path_info # 拿到访问的路径 permission_list = request.session.get("permission_list") # 从session表里面取到这个员工的所有权限 ['/order/', '/users/'] # /users/edit/3 为什么要用正则,因为/users/edit/3 与/users/edit/(/d+)不能直接匹配 import re flag = False # 加上标志位 for permission_url in permission_list: ret = re.match(permission_url, current_path) # 用正则去匹配具体的路径,成功则返回对象, 否则返回None if ret: # 如果返回对象 flag = True break if not flag: return HttpResponse("没有访问权限")
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.service.permission_li.M1', # 加在这里 ]
接下来的问题就是,加上中间件之后,登陆页面也没有权限访问了。
我们添加白名单,登陆、注册和admin页面加里即可。
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import redirect,HttpResponse,render class M1(MiddlewareMixin): def process_request(self,request): pass #/admin/login/?next=/admin/ current_path = request.path_info valid_url_menu=["/login/","/reg/","/admin/.*"] import re for valid_url in valid_url_menu: ret=re.match(valid_url,current_path) if ret: return None permission_list = request.session.get("permission_list") if not permission_list: return redirect("/login/") # /users/edit/3 import re flag = False for permission_url in permission_list: ret = re.match(permission_url, current_path) if ret: flag = True break if not flag: return HttpResponse("没有权限")