一、权限组件

1、项目与应用

  一个项目可以有多个应用;一个应用可以在多个项目下;前提:应用是组件。

2、什么是权限?

  一个包含正则表达式的url就是一个权限。

  可以理解为如下方程式:

who    what   how   ---------->True  or  Flase

3、以路飞网站为例,哪些人拥有哪些权限如何设计表

(1)初始设计

  1)用户表UserInfor

id    用户名    操作级别
1 admin 5
2 user 1

  2)权限表Permission

id    操作    操作级别
1 select 1
2 add 2
3 del 3

(2)根据url就是一个权限将表关系做如下修改

  1)用户表

name   pwd
egon 123
alex 456

  2)权限表

id           url            title
1 "/users/" "查看用户"
2 "/users/add/" "添加用户"
3 "/customer/add" "添加客户"

  3)用户与权限关系表(多对多)

id    user_id   permission_id
1 1 1
2 1 2
3 2 2

(3)以登录人egon为例访问url:http://127.0.0.1:8000/users/

def users(request):
user_id = request.session.get("user_id") # 基于对象的跨表查询
obj = UserInfor.objects.filter(pk=user_id).first()
# obj.permission.all() 拿到这个用户所有的关联权限
obj.permission.all().valuelist("url") return HttpResponse("users...")

  可以看到egon拥有查看用户权限,因此可以正常访问http://127.0.0.1:8000/users/。

(4)这种实现方式存在的问题?

  这种方式是给人定权限,往往每个人拥有多个权限,那每个人都要在用户与权限关系表拥有多条权限记录,现实中往往很多人有相同的职责和权限,则权限记录还要根据人数翻倍,数据库存储的数据量过大。

  因此应该给角色定权限,直接给人分配角色。

4、给角色定权限

(1)设计表和表关系

  1)userInfor用户表

name   pwd
egon 123
alex 456

  2)Role角色表

 id   title
1 销售员

  3)UserInfo2Role用户角色关系表(多对多)

  id     user_id    role_id
1 1 1

  4)Permission权限表

id          url            title
1 "/users/" "查看用户"
2 "/users/add/" "添加用户"
3 "/customer/add" "添加客户"

  5)Role2Permission角色权限关系表(多对多)

 id  role_id   permission_id
1 1 1
2 1 2
3 1 3

  以上就设计了一个简单的rbac数据表。

(2)什么是rbac?

  rbac就是role-based access control,也就是基于角色的访问控制

二、构建一个独立的权限管理组件(随时插拔使用)

1、创建一个django项目,建立应用app01和rbac

  

  由于要创建的权限组件是一个独立组件,新建一个rbac应用:

  (1)运行Tools——》Run manage.py Task...

  (2)在manage命令框执行:startapp rbac

manage.py@learn_rbac > startapp rbac
bash -cl "/Users/hqs/venv/bin/python /Applications/PyCharm.app/Contents/helpers/pycharm/django_manage.py startapp rbac /Users/hqs/PycharmProjects/learn_rbac"

  (3)在settings.py的INSTALLED_APPS中添加这个应用:

INSTALLED_APPS = [
...
'django.contrib.staticfiles',
'app01.apps.App01Config',
'rbac.apps.RbacConfig',
]

  这个没有添加会导致models里的内容找不到等问题。

2、构建models.py

  /rbac/models.py:

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)
url = 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

  接着进行数据迁移:

$ python3 manage.py makemigrations

$ python3 manage.py migrate

3、运用Django的admin组件进行后台数据管理

(1)创建超级用户来登录和使用admin组件

(venv)MacBook-Pro:learn_rbac hqs$ python3 manage.py createsuperuser
Username (leave blank to use 'hqs'): yuan
Email address:
Password:
Password (again):
Superuser created successfully.

  创建好新的超级用户的账号密码:yuan/yuan1234,访问并登录http://127.0.0.1:8000/admin

(2)admin注册

  /rbac/admin.py:

from django.contrib import admin

# Register your models here.
from .models import * admin.site.register(User)
admin.site.register(Role)
admin.site.register(Permission)

  注册完成页面显示如下:

  

(3)admin页面添加权限、角色、用户

  

  

  

  创建了CEO、销售、保洁三种角色:CEO具备所有权限、销售具备查看和添加用户权限、保洁只有查看用户权限。

  创建三名用户,yuan分配CEO角色、egon分配保洁、alex分配保洁和销售角色。

(4)编辑/learn_rbac/learn_rbac/urls.py

from django.contrib import admin
from django.urls import path
from app01 import views urlpatterns = [
path('admin/', admin.site.urls),
path('users/', views.users),
path('users/add/', views.add_user),
path('roles/', views.roles),
path('login/', views.login),
]

(5)编辑/learn_rbac/app01/views.py

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):
return HttpResponse("add user....") def roles(request):
role_list = Role.objects.all()
return render(request, "roles.html", locals())

4、登录验证(session permission_list)

learn_rbac/app01/views.py:

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:
# 保存登录状态,request.session ############### 在session中注册用户id ################
request.session["user_id"] = user.pk ############### 在sessions中注册权限列表 ############# # 登录成功
# 查询当前登录用户的所有角色
ret = user.roles.all()
print(ret) # <QuerySet [<Role: 保洁>, <Role: 销售>]> # 查看当前用户所有的权限
# 1、用values()来遍历QuerySet; 2、跨表查询 3、distinct去重
permissions = user.roles.all().values("permissions__url").distinct()
print(permissions) # <QuerySet [{'permissions__url': '/users/'}, {'permissions__url': '/users/add'}]> permission_list = []
for item in permissions:
permission_list.append(item["permissions__url"]) print(permission_list) # ['/users/', '/users/add'] # ret = user.roles.all().values("title", "permissions__url")
# print(ret) # <QuerySet [{'title': '保洁', 'permissions__url': '/users/'}, {'title': '销售', 'permissions__url': '/users/'}, {'title': '销售', 'permissions__url': '/users/add'}]> request.session["permission_list"] = permission_list return HttpResponse("登录成功!") return render(request, "login.html")

   注意:

(1)用request.session保存登录状态,在session中注册用户ID:

request.session["user_id"] = user.pk

  在sessions中注册权限列表:

request.session["permission_list"] = permission_list

(2)user.roles.all()查询到当前登录用户的所有角色:<QuerySet [<Role: 保洁>, <Role: 销售>]>

  user.roles.all().values("permissions__url")查询到当前用户所有权限,这里需要注意三点:1.用values()来遍历QuerySet;  2.跨表查询  3.values不会去重,需要用distinct去重。

(3)针对vlues的解析:

ret = user.roles.all().values("title", "permissions__url")
print(ret) # <QuerySet [{'title': '保洁', 'permissions__url': '/users/'}, {'title': '销售', 'permissions__url': '/users/'}, {'title': '销售', 'permissions__url': '/users/add'}]> """上面的代码可以解释为如下步骤:
temp = []
for role in user.roles.all():
temp.append({
"title": role.title,
"permissions_url": role.permissions.url,
})
"""

5、权限校验

from rbac.models import *
import re 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("没有访问权限!") def roles(request):
permission_list = request.session["permission_list"] 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("没有访问权限!") role_list = Role.objects.all()
return render(request, "roles.html", locals())

注意:

(1)利用re.match让匹配项去匹配匹配规则,确认用户是否有对应的url即权限。

import re

ret = re.match('/users/', "/users/delete/9")
print(ret) # 匹配成功:<_sre.SRE_Match object; span=(0, 7), match='/users/'> # 这两个字段一个是查询、一个是删除权限,应该是不匹配成功的
ret = re.match('^/users/$', "/users/delete/9")
print(ret) # 匹配失败:None

  第一个参数是匹配规则,第二个参数是匹配项,需要注意给匹配规则添加^和$来确保匹配规则正常生效。

(2)由于删除路径一般是"/user/delete/数字"的形式,因此在添加编辑、删除等权限是使用的url如下所示:

  

  

(3)验证这条url是否在权限组中方式:

l = ['/users/', '/users/add', '/users/delete/(\d+)', '/users/edit/(\d+)']

c_path = "/users/delete/9"

flag = False
for permission in l:
permission = "^%s$" % permission
ret = re.match(permission, c_path)
if ret:
# 匹配成功有一个对象
flag = True if flag:
print("success")

(4)可以看到这样需要在每个视图函数中添加同样的代码来实现权限控制,因此还是需要基于中间件来实现权限校验。

6、基于中间件的权限校验

import re
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse, redirect 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 # 等同于return none ############### 检验是否登录 ##############
user_id = request.session.get("user_id") if not user_id:
return redirect("/login/") ################ 校验权限 #################
permission_list = request.session.get("permission_list") 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("没有访问权限!")

注意:

(1)在这里创建了/rbac/service子目录,并在目录下创建rbac.py来自定义一个中间件。

(2)在settings中添加自定义中间件:

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
...
'rbac.service.rbac.ValidPermission',
]

(3)白名单,不需要任何权限局能访问的url

valid_url_list = ['/login/', '/reg/', '/admin/.*']
for valid_url in valid_url_list:
ret = re.match(valid_url, current_path)
if ret:
return # 等同于return none

8、分拆login视图函数,将查看当前用户所有的权限取出作为一个模块引用使用

views.py:

from rbac.service.permissions 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:
# 保存登录状态,request.session
############### 在session中注册用户id ################
request.session["user_id"] = user.pk ############### 在sessions中注册权限列表 #############
initial_session(user, request) return HttpResponse("登录成功!")
return render(request, "login.html")

/rbac/service/permissions.py:

def initial_session(user,request):
"""
查看当前用户所有的权限
:param user:
:param request:
:return:
"""
permissions = user.roles.all().values("permissions__url").distinct()
print(permissions) # <QuerySet [{'permissions__url': '/users/'}, {'permissions__url': '/users/add'}]> permission_list = []
for item in permissions:
permission_list.append(item["permissions__url"]) print(permission_list) request.session["permission_list"] = permission_list

初识rbac的更多相关文章

  1. Django - 学习目录

    Django 基础 web应用/http协议/web框架 Django简介 Django - 路由层(URLconf) Django - 视图层 Django - 模板层 Django - 模型层 - ...

  2. python全栈开发之路

    一.Python基础 python简介 python数据类型(数字\字符串\列表) python数据类型(元组\字典) python数据类型(集合) python占位符%s,%d,%r,%f prin ...

  3. 1、rbac权限组件-初识, 中间件校验1

    1.权限组件rbac 1.什么是权限 1 项目与应用 2 什么是权限? 一个包含正则表达式url就是一个权限 who what how ---------->True or Flase 2.版本 ...

  4. rbac - 初识

    一.rbac 权限组件 1 项目与应用 一个项目,可以有多个应用 一个应用,可以在多个项目下 前提:应用是组件!! 2 什么是权限? 一个包含正则表达式url就是一个权限 who what how - ...

  5. rbac权限+中间件 初识

    rbac权限+中间件 1.权限组件rbac 1.什么是权限 1 项目与应用 2 什么是权限? 一个包含正则表达式url就是一个权限 who what how ---------->True or ...

  6. django自定义rbac权限组件(二级菜单)

    一.目录结构 二.表结构设计 model.py from django.db import models # Create your models here. class Menu(models.Mo ...

  7. Android动画效果之初识Property Animation(属性动画)

    前言: 前面两篇介绍了Android的Tween Animation(补间动画) Android动画效果之Tween Animation(补间动画).Frame Animation(逐帧动画)Andr ...

  8. 初识Hadoop

    第一部分:              初识Hadoop 一.             谁说大象不能跳舞 业务数据越来越多,用关系型数据库来存储和处理数据越来越感觉吃力,一个查询或者一个导出,要执行很长 ...

  9. python学习笔记(基础四:模块初识、pyc和PyCodeObject是什么)

    一.模块初识(一) 模块,也叫库.库有标准库第三方库. 注意事项:文件名不能和导入的模块名相同 1. sys模块 import sys print(sys.path) #打印环境变量 print(sy ...

随机推荐

  1. 【BZOJ1053】[HAOI2007]反素数 (搜索+数论)

    \([POI2002][HAOI2007]\)反素数 题目描述 对于任何正整数x,其约数的个数记作\(g(x)\).例如\(g(1)=1.g(6)=4\). 如果某个正整数x满足:\(g(x)> ...

  2. [jvm]基于jvm的线程实现

    一.线程的实现 学过操作系统的肯定都知道: 进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位. 线程:是进程的一个执行单元,是进程内可调度实体. ...

  3. SDUT OJ 顺序表应用6:有序顺序表查询

    顺序表应用6:有序顺序表查询 Time Limit: 1000 ms Memory Limit: 4096 KiB Submit Statistic Discuss Problem Descripti ...

  4. 将form转为ajax提交的js代码

    参考网络代码基础上进行修改,调试通过. 在html中插入下面的代码: 函数ajaxSubmit是submit的ajax形式. 注意:这里面使用到了jquery库 //<!--将form中的值转换 ...

  5. yum国内镜像配置

    yum默认链接的还是国外的镜像,速度相对不理想,配置成国内的镜像会快很多,这里以阿里镜像为例进行配置: CentOS系统更换软件安装源 #base源#第一步:备份你的原镜像文件,以免出错后可以恢复.m ...

  6. 【算法笔记】B1032 挖掘机技术哪家强

    1032 挖掘机技术哪家强 (20 分) 为了用事实说明挖掘机技术到底哪家强,PAT 组织了一场挖掘机技能大赛.现请你根据比赛结果统计出技术最强的那个学校. 输入格式: 输入在第 1 行给出不超过 1 ...

  7. 打开页面时就提交,可以做一些自动登陆 还有SICLOGIN的测试代码

      <HTML> <head> <title> Untitled Document</title > (1)自动提交表单: <meta http- ...

  8. ansys14.0 从入门到精通

    凌桂龙 李战分 2013.2 清华大学 FLUENT流体计算应用教程 索书号:TB126-39 ZW2.1     单元 结点 和 自由度 载荷 与 边界条件 : 关系 就是约束 , 边界条件是 结构 ...

  9. Counting Divisors HDU - 6069

    设n=p_1^{c_1}p_2^{c_2}...p_m^{c_m}n=p​1​c​1​​​​p​2​c​2​​​​...p​m​c​m​​​​,则d(n^k)=(kc_1+1)(kc_2+1)...( ...

  10. [转] docker save与docker export的区别

    [From]http://cnodejs.org/topic/59a2304f7aeedce818249eeb 很久没有写博客了,坟头草都长了老高了.写博客要靠惯性,一旦停下来时间长了,就很难再坚持下 ...