在上一篇文章中,我的中间件是 保存在我的web 业务app 中的。
但是rbac我想要完成的是一个 组件的功能, 所以这个验证的 中间件, 何不放到rbac的app之中:
为了太乱先放一个项目的目录图片:
不要忘记我们的目的: 做一个 可以灵活使用的rbac 权限组件:
先看看setting中的配置:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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', }, } }
我在配置文件中 添加的这两个, 配置项。
# session-key配置 为了解决以后我可能想要更换 session-key的 问题
PERMISSIONS_SESSION_KEY = "permissions__url"
# 配置权限 白名单 为了一些我并不想 通过rbac组件进行权限验证的一些白名单
VALID_URL_LIST = ["/login/", "/admin/"]
然后是 权限认证的中间件:
通过引入settings 的到, session-key 和 白名单。 在中间件进行验证
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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("无权访问")
然后是modles:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
然后是 web 业务的视图函数中:
在这里我们直接引入rbac组件中 service.init_permission 权限初始化函数 init_permission(current_user, request)
来进行,权限的初始化。 并且跳转到 主页面。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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())