在上一篇文章中,我的中间件是 保存在我的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

 

posted on 2019-04-12 15:43  rookiehbboy  阅读(251)  评论(0编辑  收藏  举报