一、什麼是權限
1 項目與應用
2 什麼是權限?
一個包含正則表達式url就是一個權限
who what how ---------->True or Flasejavascript
二、版本: 用戶--》角色--》權限
UserInfor name pwd roles name pwd egon 123 alex 456 alex 456 alex 456 alex 456 alex 456 alex 456 alex 456 alex 456 Role title=....... permissions=...... id title 1 銷售員 UserInfor2Role id user_id role_id 1 1 1 Permission url=..... title=.... id url title 1 "/users/" "查看用戶" 2 "/users/add/" "添加用戶" 3 "/customer/add" "添加客戶" Role2Permission id role_id permission_id 1 1 1 2 1 2 3 1 3 3 rbac(role-based access control)
3.數據表的初步設計
from django.db import models # Create your models here. class User(models.Model): #用戶表 name=models.CharField(max_length=32) pwd=models.CharField(max_length=32) roles=models.ManyToManyField(to="Role") #一個用戶能夠有多個角色,一個角色能夠爲多個用戶所擁有。 def __str__(self): return self.name class Role(models.Model): title=models.CharField(max_length=32) permissions=models.ManyToManyField(to="Permission") #一個角色有多個權限,一個權限也能夠是多個角色擁有。 def __str__(self): return self.title class Permission(models.Model): title=models.CharField(max_length=32) #權限明珠城 url=models.CharField(max_length=32) #權限的url action=models.CharField(max_length=32,default="") #權限操做(add,list,edit,delete) group=models.ForeignKey("PermissionGroup",default=1,on_delete=models.CASCADE) def __str__(self): return self.title class PermissionGroup(models.Model): title=models.CharField(max_length=32) def __str__(self): return self.title
1)項目目錄結構
2)數據庫表
3)admin添加數據
建立超級用戶 alexhtml
註冊數據表java
from django.contrib import admin # Register your models here. from .models import * admin.site.register(User) admin.site.register(Role) admin.site.register(Permission)
四、登陸驗證
一、session中註冊用戶,權限
1.在session中註冊用戶ID
request.session['user_id'] = user.pk
2.初始化 permission_list 並註冊到session 中
initial_session(user,request)
if 登陸成功: user=User.objects.filter(name=user,pwd=pwd).first() 只要這個user對象存在 initial_session(user,request)經過傳入登陸的user對象和request 能夠把當前登陸用戶的權限列表和user_id註冊到session中。 else: redirect("/login/") ** 把設置session單獨作成一個函數接口下降耦合,只須要傳入登陸用戶的對象。 def initial_session(user,request): permissions = user.roles.all().values("permissions__url").distinct() #經過登陸用戶對象查找到全部的角色對象QuerySet,而後跨表到權限表取到URL,作一個去重
<QuerySet [{'permissions__url': '/users/'}, {'permissions__url': '/users/add'}, {'permissions__url': '/users/delete/(\\d+)'}]>
注意點:正則表達式
permission = user.roles.all().values('permission__url').distinct()
#將這些權限取到對應的URL而且添加到列表中,設置在session中。 permission_list = [] for item in permissions: permission_list.append(item["permissions__url"]) print(permission_list) request.session["permission_list"] = permission_list
二、解耦
def initial_session(request,user): permissions = user.roles.all().values("permissions__url").distinct() permission_list = [] for item in permissions: permission_list.append(item['permissions__url']) print(permission_list) # ['/users/', '/users/add', '/users/delete/(\\d+)', '/users/edit/(\\d+)'] request.session["permission_list"] = permission_list """ values : for role in user.roles.all(): # <QuerySet [<Role: 保潔>, <Role: 銷售>]> temp.append({ "title":role.title, "permissions_url":role.permissions.all() }) # <QuerySet [{'title': '保潔', 'permissions__url': '/users/'}, # {'title': '銷售', 'permissions__url': '/users/'}, # {'title': '銷售', 'permissions__url': '/users/add'}]> """
四、基於中間件的權限校驗
一、middleware如何構造
設置中添加中間件"rbac.service.rbac.ValidPermissionMiddleware"
二、正則匹配
from django.test import TestCase # Create your tests here. # 當前path 如何與 paths匹配 # 不能用in /users/delete/9 # 正則匹配 li = ['/users/', '/users/add', '/users/delete/(\\d+)', '/users/edit/(\\d+)'] c_path = "/users/delete/9" import re flag = False for permission in li: permission = "^%s$" % permission ret = re.match(permission, c_path) if ret: flag = True break if flag: print("success") # ret = re.match("/users/", "/users/delete/9") ret = re.match("^/users/$", "/users/delete/9") print(ret)
三、構建中間件
import re from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse,redirect class ValidPermissionMiddleWare(MiddlewareMixin): def process_request(self,request): # 當前訪問路徑 current_path = request.path_info #1層校驗 檢查是否屬於白名單 valid_url_list=["/login/","/reg/","/admin/.*"] for valid_url in valid_url_list: ret=re.match(valid_url,current_path) if ret: return None #2層校驗 校驗是否登陸 user_id=request.session.get("user_id") if not user_id: return redirect("/login/") # 3層校驗校驗權限 permission_list = request.session.get("permission_list",[]) #['/users/', '/users/add', '/users/delete/(\\d+)', 'users/edit/(\\d+)'] flag = False for permission in permission_list: #此處作一個RE拼接,否則容易匹配失敗 permission = "^%s$" % permission ret = re.match(permission, current_path) if ret: flag = True break if not flag: return HttpResponse("沒有訪問權限!") #在此處就直接告訴用戶沒有權限,再也不進入視圖。 return None
四、views視圖,url
url.py數據庫
from django.contrib import admin from django.urls import path,re_path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), re_path(r'^users/$',views.users), re_path(r'^users/add/$',views.add_user), re_path(r'^roles/$',views.roles), re_path(r'^login/$',views.login), ]
viewsdjango
from django.shortcuts import render, HttpResponse # Create your views here. from rbac.models import * def users(request): user_list = User.objects.all() return render(request, "users.html", locals()) def add_user(request): """ permission_list = request.session["permission_list"] # # ['/users/', '/users/add', '/users/delete/(\\d+)', '/users/edit/(\\d+)'] current_path = request.path_info flag = False for permission in permission_list: permission = "^%s$"%permission ret = re.match(permission, current_path) if ret: flag = True break if not flag: return HttpResponse("沒有訪問權限") """ return HttpResponse('add user') def roles(request): role_list = Role.objects.all() print(role_list) # 方式2 middleware """ # 方式1 permission_list = request.session["permission_list"] # # ['/users/', '/users/add', '/users/delete/(\\d+)', '/users/edit/(\\d+)'] current_path = request.path_info flag = False for permission in permission_list: permission = "^%s$"%permission ret = re.match(permission, current_path) if ret: flag = True break if not flag: return HttpResponse("沒有訪問權限") """ return render(request, "roles.html", locals()) from rbac.service.perssions import * def login(request): if request.method == "POST": user = request.POST.get("user") pwd = request.POST.get("pwd") user = User.objects.filter(name=user, pwd=pwd).first() if user: ############## 在session中註冊用戶 request.session['user_id'] = user.pk ############# 在session中註冊權限list # 查詢當前登陸用戶的全部角色 # ret = user.roles.all() # print(ret) # <QuerySet [<Role: 保潔>, <Role: 銷售>]> # 查詢當前登陸用戶的全部權限 initial_session(request, user) return HttpResponse("登陸成功") return render(request, 'login.html', locals())
注意點
1.白名單,不須要任何權限的url
valid_url_list = ['/login/', '/reg/', '/admin/.*']
for valid_url in valid_url_list:
ret = re.match(valid_url, current_path)
if ret:
return
正則匹配
2.校驗是否登陸,
user_id = request.session.get('user_id')
if not user_id:
return redirect('/login/')
3.校驗權限(^ $ / 正則)
permission_list = request.session.get('permission_list',[])
flag = False
for permission in permission_list:
# ['/users/', '/users/add/', '/users/edit/(\\d+)/', '/users/delete/(\\d+)/']
# 須要 ^ $ 限定!!
permission = "^%s$" % permission
# 正則
ret = re.match(permission, current_path)
if ret:
flag = True
break
if not flag:
return HttpResponse('無訪問權限!')
四、總結:關於rbac
關於rbac: (1) 建立表關係: class User(models.Model): name=models.CharField(max_length=32) pwd=models.CharField(max_length=32) roles=models.ManyToManyField(to="Role") def __str__(self): return self.name class Role(models.Model): title=models.CharField(max_length=32) permissions=models.ManyToManyField(to="Permission") def __str__(self): return self.title class Permission(models.Model): title=models.CharField(max_length=32) url=models.CharField(max_length=32) def __str__(self):return self.title (2) 基於admin錄入數據 (3) 登陸校驗: if 登陸成功: 查詢當前登陸用戶的權限列表註冊到session中 (4) 校驗權限(中間件的應用) class ValidPermission(MiddlewareMixin): def process_request(self,request): # 當前訪問路徑 current_path = request.path_info # 檢查是否屬於白名單 valid_url_list=["/login/","/reg/","/admin/.*"] for valid_url in valid_url_list: ret=re.match(valid_url,current_path) if ret: return None # 校驗是否登陸 user_id=request.session.get("user_id") if not user_id: return redirect("/login/") # 校驗權限 permission_list = request.session.get("permission_list",[]) # ['/users/', '/users/add', '/users/delete/(\\d+)', 'users/edit/(\\d+)'] flag = False for permission in permission_list: permission = "^%s$" % permission ret = re.match(permission, current_path) if ret: flag = True break if not flag: return HttpResponse("沒有訪問權限!") return None