Django--权限组件 创建组件

需求分析:

 创建独立app, rbac        

##注意:

  app创建后需要注册到setting.py中

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',
]

设计权限表

方案1:

创建用户表和创建权限表,然后两个表通过一个用户可能有多各权限 然后一个权限可以属于多个用户,所以两张表创建多对多关系,但是存在很多用户有相同的权限字段,所以参考方案二。

方案2:

创建用户表、创建权限表和角色表,为每个角色添加权限,然后用户通过角色获取自己的权限,分析如下所示

     
            用户表:
                ID          username        password    ....
                 1           番禺                 123
                 2           夹缝                 123
                 3           果冻                 123
                 4           鲁宁                 123
                 
                 
            角色表:
                ID          title 
                 1            CEO
                 2            CTO
                 4            COO
                 5            部门经理
                 6            技术员
                 
            用户和角色关系表:
                用户ID       角色ID
                  1            1
                  1            2
                  1            4
                  2            5
                  3            6
                  4            6
        
            权限表:
                ID          url                         title
                 1         /index/                      首页
                 2         /userinfo/                   用户列表
                 3         /userinfo/add/               添加用户
                 4         /userinfo/del/(d+)/         删除用户
                 5         /userinfo/edit/(d+)/        修改用户
        
            
            角色权限关系表:
                角色ID           权限ID 
                  1                1

具体表设计如下所示:

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=64)
    is_menu = models.BooleanField(verbose_name="是否是菜单")

    class Meta:
        verbose_name_plural = "权限表"

    def __str__(self):
        return self.title

class User(models.Model):
    """
    用户表
    """
    username = 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)
    class Meta:
        verbose_name_plural = "用户表"

    def __str__(self):
        return self.username

class Role(models.Model):
    """
    角色表
    """
    title = models.CharField(max_length=32)
    permissions = models.ManyToManyField(verbose_name='具有的所有权限',to='Permission',blank=True)
    class Meta:
        verbose_name_plural = "角色表"

    def __str__(self):
        return self.title

 然后通过管理类同步数据库,添加数据。

3. 权限录入:
        CEO:番禺
            /userinfo/
            /userinfo/add/
            /userinfo/edit/(d+)/
            /userinfo/del/(d+)/
            /order/
            /order/add/
            /order/edit/(d+)/
            /order/del/(d+)/
        总监:鲁宁
            /userinfo/
            /userinfo/add/
            /order/
            /order/add/
        经理:肾松
            /userinfo/
            /order/
        业务员:肾松,文飞,成栋
            /order/

配置用户调用接口

1. 本地化用户权限

在rbac中创建一个初始化文件,用于本地化权限信息,使调用者方便调用

from django.conf import settings

def init_permission(request,user):
    """
    本地化用户权限"""
    # 获取当前用户所有权限(重)
    permission_list = user.roles.values('permissions__url').distinct()
    request.session[settings.PERMISSION_LIST] = [url['permissions__url'] for url in permission_list]

2. 通过中间键进行用户请求url过滤

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.middleware.PermissionMiddleware', # 将添加的中间件配置到settings中
]
#####################confirm###################
SESSION_KEY = 'auth_user'
PERMISSION_LIST = 'permission_list'

INVALIDATION_LIST = [
    '/admin.*',
    '/login/',
    '/register/',
]

创建middleware.py

# encoding:utf-8
# Author:"richie"
# Date:11/7/2017
import re
from django.conf import settings
from django.shortcuts import HttpResponse,redirect
class MiddlewareMixin(object):
    def __init__(self, get_response=None):
        self.get_response = get_response
        super(MiddlewareMixin, self).__init__()

    def __call__(self, request):
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request)
        if not response:
            response = self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response


class PermissionMiddleware(MiddlewareMixin):

    def process_request(self, request):

        current_path = request.path_info


        for url in settings.INVALIDATION_LIST:
            if re.match(url,current_path):
                return None

        permission_list = request.session.get(settings.PERMISSION_LIST)

        if not permission_list:
            return redirect('/login/')

        flag = False

        for url in permission_list:
            regular = "^{0}$".format(url)  # 因为添加url的时候没有添加严格匹配的规则,所以在这里转格式
            if re.match(regular,current_path):
                flag = True
                break

        if not flag:
            # 没有匹配上
            return HttpResponse('无权访问')

权限组件使用

分配url,

from django.conf.urls import url
from app01 import views
urlpatterns = [
    url(r'^login/', views.login, name='login'),
    url(r'^index/', views.home, name='home'),
    url(r'^userinfo/', views.home, name='home'),
    url(r'^userinfo/add', views.home, name='home'),
    url(r'^order/', views.home, name='home'),
    url(r'^order/add', views.home, name='home'),
]

定义视图函数:

from django.shortcuts import render,redirect
from django.conf import settings
from rbac.models import User
from rbac.service import init_permission
# Create your views here.

class UserLoginForm(forms.ModelForm):
    """
    定义用户登录的from表单
    """
    class Meta:
        model  = models.User
        fields = ['username','password']

def login(request):
    if request.method == 'POST':
        # 获取用户from表单数据
        login_form = forms.UserLoginForm(request.POST)
        # 数据格式验证
        if login_form.is_valid():
            #用户认证
            username = login_form.cleaned_data.get('username')
            password = login_form.cleaned_data.get('password')
            # 用户数据数据库验证
            user =User.objects.filter(username=username,password=password).first()
            if user:
                #初始化权限系统
                init_permission(request,user)
                # 添加用户信息
                request.session[settings.SESSION_KEY] = {'uid':user.id,'username':username}
                return redirect('/home/')
            else:
                # 登录失败  添加错误信息
                login_form.errors.update({'user_error': '用户名或密码错误'})
    else:
        login_form = forms.UserLoginForm()

    return render(request, 'login.html',{'form':login_form})

def home(request):
    """
    主页面
    :param request: 
    :return: 
    """
    
    #获取用户名信息
    username = request.session.get(settings.SESSION_KEY).get('username')
    return render(request,'home.html',locals())

3. 定义模板页面

login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>

<form method="post" novalidate>{% csrf_token %}
    {{ form.errors.user_error }}
    {% for filed in form %}
        <p>{{ filed.label_tag }}{{ filed }}</p>
        <p>{{ filed.errors.as_text }}</p>
    {% endfor %}

    <input type="submit" value="提交">
</form>

</body>
</html>

定义home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
{{ username }}
</body>
</html>