权限管理项目笔记
创建项目
创建一个项目名为PermissionSystems
django-admin startproject PermissionSystems
进入项目目录,创建两个应用,一个专用权限管理的rbac,一个用于其他的app01
python manage.py startapp rbac
python manage.py startapp app01
rbac:基于角色的权限访问控制(Role-Based Access Control)
用Pycharm打开项目,注册app
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rbac.apps.RbacConfig',
'app01.apps.App01Config',
]
templates配置
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
设计rbac/models.py 数据库表
from django.db import models
class Permission(models.Model):
"""
权限表
"""
title = models.CharField(max_length=32)
url = models.CharField(max_length=128)
def __str__(self):
return self.title
class Role(models.Model):
"""
角色
"""
title = models.CharField(max_length=32)
permissions = models.ManyToManyField(to='Permission', blank=True)
def __str__(self):
return self.title
class UserInfo(models.Model):
"""
用户表
"""
name = models.CharField(max_length=32)
password = models.CharField(max_length=64)
email = models.CharField(max_length=32)
roles = models.ManyToManyField(to='Role')
def __str__(self):
return self.name
生成数据库
python manage.py makemigrations
python manage.py migrate
注册rbac.admin.py用于用于插入数据
from django.contrib import admin
from . import models
admin.site.register(models.Permission)
admin.site.register(models.Role)
admin.site.register(models.UserInfo)
创建超级用户
python manage.py createsuperuser
用户名 superuser
密码 root123456
启动服务,进入admin后台插入数据
python manage.py runserver
访问http://127.0.0.1:8000/admin/
更改admin.py里的字段,显示两列
from django.contrib import admin
from . import models
class PermissionCongfig(admin.ModelAdmin):
list_display = ['title', 'url']
admin.site.register(models.Permission, PermissionCongfig)
admin.site.register(models.Role)
admin.site.register(models.UserInfo)
权限表Permission
| TITLE | URL | |
|---|---|---|
| 编辑订单 | /orders/edit/(\d+)/ | |
| 删除订单 | /orders/del/(\d+)/ | |
| 添加订单 | /orders/add/ | |
| 订单列表 | /orders/ | |
| 编辑用户 | /users/edit/(\d+)/ | |
| 删除用户 | /users/del/(\d+)/ | |
| 添加用户 | /users/add/ | |
| 用户列表 | /users/ |
添加角色
销售 订单列表、添加订单
销售主管 用户列表和所有订单操作
老板 所有操作权限
创建用户
| User | Role |
|---|---|
| 王庆帅 | 老板 |
| 王庆酷 | 销售主管 |
| 王庆美 | 销售 |
| 王庆丑 | 销售 |
登录页面,筛选出登录用户的权限
urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.log_in),
]
app01/views.py
from django.shortcuts import render, HttpResponse
from rbac import models
def log_in(request):
if request.method == "GET":
return render(request, 'app01/login.html')
if request.method == "POST":
user = request.POST.get('user')
pwd = request.POST.get('pwd')
user = models.UserInfo.objects.filter(name=user, password=pwd).first()
if user:
# 根据当前用户找到已知的所有权限ORM跨表查询,过滤
permission_list = user.roles.filter(permissions__title__isnull=False).values('permissions__title',
'permissions__url').distinct()
for permission in permission_list:
print(permission)
return HttpResponse('登录成功')
return render(request, 'app01/login.html')
templates/app01/login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post">
{% csrf_token %}
<input type="text" name="user" placeholder="用户名">
<input type="password" name="pwd" placeholder="密码">
<input type="submit" value="登录">
</form>
</body>
</html>
这下可以筛选出对应的权限
比如王庆帅登录,筛选出:
{'permissions__title': '用户列表', 'permissions__url': '/users/'}
{'permissions__title': '添加用户', 'permissions__url': '/users/add/'}
{'permissions__title': '删除用户', 'permissions__url': '/users/del/(\\d+)/'}
{'permissions__title': '编辑用户', 'permissions__url': '/users/edit/(\\d+)/'}
{'permissions__title': '订单列表', 'permissions__url': '/orders/'}
{'permissions__title': '添加订单', 'permissions__url': '/orders/add/'}
{'permissions__title': '删除订单', 'permissions__url': '/orders/del/(\\d+)/'}
{'permissions__title': '编辑订单', 'permissions__url': '/orders/edit/(\\d+)/'}
上面的权限permissions__url数据应该加入session里。
from django.shortcuts import render, HttpResponse
from rbac import models
def log_in(request):
if request.method == "GET":
return render(request, 'app01/login.html')
if request.method == "POST":
user = request.POST.get('user')
pwd = request.POST.get('pwd')
user = models.UserInfo.objects.filter(name=user, password=pwd).first()
if user:
# 根据当前用户找到已知的所有权限ORM跨表查询,过滤
permission_list = user.roles.filter(permissions__title__isnull=False).values('permissions__title',
'permissions__url').distinct()
url_list = []
for permission in permission_list:
url_list.append(permission['permissions__url'])
request.session['xxx'] = url_list
return HttpResponse('登录成功')
return render(request, 'app01/login.html')
def users(request):
# 获取当前访问的URL : request.path_info
print('当前访问的url', request.path_info)
# 获取当前用户的session里的url
url_list = request.session['xxx']
for reg in url_list:
print(reg)
return HttpResponse('用户列表')
urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.log_in),
url(r'^users/', views.users),
]
登录用户王庆帅,然后在访问http://127.0.0.1:8000/users/
结果
当前访问的url /users/
/users/
/users/add/
/users/del/(\d+)/
/users/edit/(\d+)/
/orders/
/orders/add/
/orders/del/(\d+)/
/orders/edit/(\d+)/
可以看到还有url里面有(\d+)的url,因此这里不应该用等号比较,而是用正则。
原理:
import re
current_url = '/uasdfasdfsers/'
url_list = [
'/users/',
'/users/del/(\d+)',
]
flag = False
for reg in url_list:
if re.match(reg,current_url):
flag = True
break
if not flag:
print('无权限访问')
else:
print('有权限')
修改如下:
from django.shortcuts import render, HttpResponse
from rbac import models
import re
def log_in(request):
if request.method == "GET":
return render(request, 'app01/login.html')
if request.method == "POST":
user = request.POST.get('user')
pwd = request.POST.get('pwd')
user = models.UserInfo.objects.filter(name=user, password=pwd).first()
if user:
# 根据当前用户找到已知的所有权限ORM跨表查询,过滤
permission_list = user.roles.filter(permissions__title__isnull=False).values('permissions__title',
'permissions__url').distinct()
url_list = []
for permission in permission_list:
url_list.append(permission['permissions__url'])
request.session['xxx'] = url_list
return HttpResponse('登录成功')
return render(request, 'app01/login.html')
def users(request):
# 获取当前访问的URL : request.path_info
# 获取当前用户的session里的url
url_list = request.session['xxx']
# 进行对比
flag = False
for reg in url_list:
if re.match(reg, request.path_info):
flag = True
if not flag:
return HttpResponse("无权访问")
return HttpResponse('用户列表')
中间件的使用
上面这个是用户权限的认证。我们还有订单的认证。是不是还要在写一遍一样的方法?
此时我们想到了中间件!(而不是装饰器,装饰器也得都加上啊),对所有的请求做批量处理,用中间件是最简便的。
在rbac下创建service\init_permission.py用于初始化权限。
在rbac下创建middlewares\rbac.py中间件
并将中间件,session,白名单写到配置文件
service\init_permission.py
# -*- coding: utf-8 -*-
from django.conf import settings
from django.shortcuts import HttpResponse
def init_permission(user, request):
"""
获取当前用户并放入到session中
:param user:
:param request:
:return:
"""
# 根据当前用户找到已知的所有权限ORM跨表查询,过滤
permission_list = user.roles.filter(permissions__title__isnull=False).values('permissions__title',
'permissions__url').distinct()
url_list = []
for permission in permission_list:
url_list.append(permission['permissions__url'])
request.session[settings.PERMISSION_SESSION_KEY] = url_list
rbac.py
# -*- coding: utf-8 -*-
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse
import re
from django.conf import settings # 导入全局settings
class RbacMiddleware(MiddlewareMixin):
def process_request(self, request):
# 如果的登录界面,直接return None 通过此中间件
# 获取白名单,让白名单中的所有url和当前访问url匹配
for reg in settings.PERMISSION_VALID_URL:
if re.match(reg, request.path_info):
return None
# 获取当前访问的URL : request.path_info
# 获取当前用户的session里的url
url_list = request.session.get(settings.PERMISSION_SESSION_KEY)
# 获取权限
if not url_list:
return HttpResponse("为获取到当前用户的权限信息,无法访问")
# 对用户请求的url进行匹配
flag = False
for reg in url_list:
if re.match(reg, request.path_info):
flag = True
if not flag:
return HttpResponse("无权访问")
# 如果有权限不return 默认return None 继续往后走
app01/views.py其中from django.conf import settings导入的是全局的settings
from django.shortcuts import render, HttpResponse
from rbac import models
import re
from django.conf import settings
from rbac.service.init_permission import init_permission
def log_in(request):
if request.method == "GET":
return render(request, 'app01/login.html')
if request.method == "POST":
user = request.POST.get('user')
pwd = request.POST.get('pwd')
user = models.UserInfo.objects.filter(name=user, password=pwd).first()
if user:
# 初始化权限信息
init_permission(user, request)
return HttpResponse('登录成功')
return render(request, 'app01/login.html')
def users(request):
return HttpResponse("用户列表")
def orders(request):
return HttpResponse("订单列表")
urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.log_in),
url(r'^users/', views.users),
url(r'^orders/', views.orders),
]
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.middlewares.rbac.RbacMiddleware',
]
权限相关配置
# ####################### 权限相关配置 ########################
PERMISSION_SESSION_KEY = "xxx"
PERMISSION_VALID_URL = [
'/login/',
'/admin/.*',
]
解决一个bug。进入admin.把角色销售的添加订单权限去掉。
写一个添加订单的函数,发现王庆丑也能访问,解决方案,给url加上起始符和终止符
rbac.py
# -*- coding: utf-8 -*-
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse
import re
from django.conf import settings # 导入全局settings
class RbacMiddleware(MiddlewareMixin):
def process_request(self, request):
# 如果的登录界面,直接return None 通过此中间件
# 获取白名单,让白名单中的所有url和当前访问url匹配
for reg in settings.PERMISSION_VALID_URL:
if re.match(reg, request.path_info):
return None
# 获取当前访问的URL : request.path_info
# 获取当前用户的session里的url
url_list = request.session.get(settings.PERMISSION_SESSION_KEY)
# 获取权限
if not url_list:
return HttpResponse("未获取到当前用户的权限信息,无法访问")
# 对用户请求的url进行匹配
flag = False
for reg in url_list:
reg = "^%s$" % (reg,) # /orders/add/与/orders/是有区别的。加上起始符,终止符来进行约束。
print(reg)
if re.match(reg, request.path_info):
flag = True
if not flag:
return HttpResponse("无权访问")
# 如果有权限不return 默认return None 继续往后走
urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/$', views.log_in),
url(r'^users/$', views.users),
url(r'^orders/add/$', views.orders_add),
url(r'^orders/$', views.orders),
]
更改数据库表,增加权限组
class PermissionGroup(models.Model):
"""
权限组
"""
caption = models.CharField(max_length=32)
def __str__(self):
return self.caption
1 用户组
2 订单组
权限与组直接建立关系
class Permission(models.Model):
"""
权限表
"""
title = models.CharField(max_length=32)
url = models.CharField(max_length=128)
group = models.ForeignKey(to='PermissionGroup',default=1)
def __str__(self):
return self.title
admin.py里再添加个字段
class PermissionCongfig(admin.ModelAdmin):
list_display = ['title', 'url','group']
进入admin后台把订单改成订单组
再给Permission加一个code字段
class Permission(models.Model):
"""
权限表
"""
title = models.CharField(max_length=32)
url = models.CharField(max_length=128)
code = models.CharField(max_length=16, default='list')
group = models.ForeignKey(to='PermissionGroup', default=1)
def __str__(self):
return self.title
code就是一个代号,给url一个代号用着方便
| TITLE | URL | GROUP | CODE | |
|---|---|---|---|---|
| 编辑订单 | /orders/edit/(\d+)/ | 订单组 | edit | |
| 删除订单 | /orders/del/(\d+)/ | 订单组 | del | |
| 添加订单 | /orders/add/ | 订单组 | add | |
| 订单列表 | /orders/ | 订单组 | list | |
| 编辑用户 | /users/edit/(\d+)/ | 用户组 | edit | |
| 删除用户 | /users/del/(\d+)/ | 用户组 | del | |
| 添加用户 | /users/add/ | 用户组 | add | |
| 用户列表 | /users/ | 用户组 | list |
权限初始化
# -*- coding: utf-8 -*-
from django.conf import settings
from django.shortcuts import HttpResponse
def init_permission(user, request):
"""
获取当前用户并放入到session中
:param user:
:param request:
:return:
"""
# 根据当前用户找到已知的所有权限ORM跨表查询,过滤
permission_list = user.roles.filter(permissions__title__isnull=False).values('permissions__title',
'permissions__url',
'permissions__group_id',
'permissions__code').distinct()
url_list = []
for permission in permission_list:
url_list.append(permission['permissions__url'])
request.session[settings.PERMISSION_SESSION_KEY] = url_list

浙公网安备 33010602011771号