在上一篇文章中,我的中间件是 保存在我的web 业务app 中的。
但是rbac我想要完成的是一个 组件的功能, 所以这个验证的 中间件, 何不放到rbac的app之中:
为了太乱先放一个项目的目录图片:
不要忘记我们的目的: 做一个 可以灵活使用的rbac 权限组件:
先看看setting中的配置:
import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'o+ym86530)hs=+26$$n=+l(w$belc-3uu0aa%9+*(snlac-5@a' # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rbac.apps.RbacConfig',
'web.apps.WebConfig',
] # 编写中间件,对用户权限,进行校验
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",
] ROOT_URLCONF = 'crm_learn.urls' 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',
],
},
},
] WSGI_APPLICATION = 'crm_learn.wsgi.application' # Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
} # Password validatiALLOWED_HOSTSon
# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
] # Internationalization
# https://docs.djangoproject.com/en/2.1/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/ STATIC_URL = '/static/' # ################## 默认文件上传配置 ########################
from django.core.files.uploadhandler import MemoryFileUploadHandler
from django.core.files.uploadhandler import TemporaryFileUploadHandler # List of upload handler classes to be applied in order.
FILE_UPLOAD_HANDLERS = [
'django.core.files.uploadhandler.MemoryFileUploadHandler',
'django.core.files.uploadhandler.TemporaryFileUploadHandler',
] # Maximum size, in bytes, of a request before it will be streamed to the
# file system instead of into memory.
# 允许内存中上传文件的大小
# 合法:InMemoryUploadedFile对象(写在内存) -> 上传文件小于等于 FILE_UPLOAD_MAX_MEMORY_SIZE
# 不合法:TemporaryUploadedFile对象(写在临时文件) -> 上传文件大于 FILE_UPLOAD_MAX_MEMORY_SIZE 且 小于 DATA_UPLOAD_MAX_MEMORY_SIZE FILE_UPLOAD_MAX_MEMORY_SIZE = 2621440 # i.e. 2.5 MB # Maximum size in bytes of request data (excluding file uploads) that will be
# read before a SuspiciousOperation (RequestDataTooBig) is raised.
# 允许上传内容的大小(包含文件和其他请求内容)
DATA_UPLOAD_MAX_MEMORY_SIZE = 2621440 # i.e. 2.5 MB # Maximum number of GET/POST parameters that will be read before a
# SuspiciousOperation (TooManyFieldsSent) is raised.
# 允许的上传文件数
DATA_UPLOAD_MAX_NUMBER_FIELDS = 1000 # Directory in which upload streamed files will be temporarily saved. A value of
# `None` will make Django use the operating system's default temporary directory
# (i.e. "/tmp" on *nix systems).
# 临时文件夹路径
FILE_UPLOAD_TEMP_DIR = None # The numeric mode to set newly-uploaded files to. The value should be a mode
# you'd pass directly to os.chmod; see https://docs.python.org/3/library/os.html#files-and-directories.
# 文件权限
FILE_UPLOAD_PERMISSIONS = None # The numeric mode to assign to newly-created directories, when uploading files.
# The value should be a mode as you'd pass to os.chmod;
# see https://docs.python.org/3/library/os.html#files-and-directories.
# 文件夹权限
FILE_UPLOAD_DIRECTORY_PERMISSIONS = None # session-key配置
PERMISSIONS_SESSION_KEY = "permissions__url" # 配置权限 白名单
VALID_URL_LIST = ["/login/", "/admin/"] LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
settiongs
我在配置文件中 添加的这两个, 配置项。
# session-key配置 为了解决以后我可能想要更换 session-key的 问题
PERMISSIONS_SESSION_KEY = "permissions__url"
# 配置权限 白名单 为了一些我并不想 通过rbac组件进行权限验证的一些白名单
VALID_URL_LIST = ["/login/", "/admin/"]
然后是 权限认证的中间件:
通过引入settings 的到, session-key 和 白名单。 在中间件进行验证
rom django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
from django.conf import settings
import re class RbacMiddleware(MiddlewareMixin):
'''用户权限信息的校验'''
def process_request(self, request):
'''当用户请求进入时 触发执行'''
'''
1. 获取当前用户请求的url
2. 获取当前用户在session中保存的 权限列表 [......]
3. 当前请求url 在 session中, 就可以,进行访问
'''
current_url = request.path_info
for valid_url in settings.VALID_URL_LIST:
if re.match(valid_url, current_url): # 先一步进行白名单的验证
return None
permission_list = request.session.get(settings.PERMISSIONS_SESSION_KEY) if not permission_list:
return HttpResponse("您没有访问权限...请联系管理员")
flag = False
for url in permission_list:
reg = "^%s$" % url
if re.match(reg, current_url):
flag = True
break
if not flag:
return HttpResponse("无权访问")
rbac.middlewares.rbac.RbacMiddleware
然后是modles:
from django.db import models class Permission(models.Model):
"""
权限表
"""
title = models.CharField(verbose_name='标题', max_length=32)
url = models.CharField(verbose_name='含正则的URL', max_length=128) def __str__(self):
return self.title class Role(models.Model):
"""角色"""
title = models.CharField(verbose_name='角色名称', max_length=32)
permissions = models.ManyToManyField(verbose_name='拥有的所有权限', to='Permission', blank=True) def __str__(self):
return self.title class UserInfo(models.Model):
"""
用户表
"""
name = models.CharField(verbose_name='用户名', max_length=32)
password = models.CharField(verbose_name='密码', max_length=64)
email = models.CharField(verbose_name='邮箱', max_length=32)
roles = models.ManyToManyField(verbose_name='拥有的所有角色', to='Role', blank=True) def __str__(self):
return self.name
rbac.models
然后是 web 业务的视图函数中:
在这里我们直接引入rbac组件中 service.init_permission 权限初始化函数 init_permission(current_user, request)
来进行,权限的初始化。 并且跳转到 主页面。
from django.shortcuts import HttpResponse, redirect, render
from rbac.models import *
from rbac.service.init_permission import init_permission def login(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd") current_user = UserInfo.objects.filter(name=user, password=pwd).first() if not current_user:
return render(request, "login.html", {"msg": "username or password is wrong"}) init_permission(current_user, request)
return redirect("/customer/list/")
return render(request, "login.html", locals())
web.views.account