python 权限系统设计

权限系统表结构的设计

from django.db import models

# Create your models here.
class UserInfo(models.Model):
    '''
    用户表
    '''
    username=models.CharField(max_length=32,verbose_name='用户名')
    password=models.CharField(max_length=64,verbose_name='密码')
    roles=models.ManyToManyField(to='Role',verbose_name='拥有角色',)
class Role(models.Model):
    '''
    角色表
    '''
    title=models.CharField(max_length=32,verbose_name='角色名称')
    permissions=models.ManyToManyField(to='Permission',verbose_name='拥有权限')
    def __str__(self):
        return self.title

class Permission(models.Model):
    '''
    权限表
    '''
    title=models.CharField(max_length=32,verbose_name='权限名称')
    url=models.CharField(max_length=255,verbose_name='含权限的URL')
    code=models.CharField(max_length=32,verbose_name='权限代码')
    group=models.ForeignKey(to='PermissionGroup',verbose_name='所属权限组',on_delete=True)
    group_menu=models.ForeignKey(verbose_name='组内菜单',to='self',null=True,blank=True,related_name='gxx',on_delete=True)
class PermissionGroup(models.Model):
    '''
    权限组
    '''
    caption=models.CharField(max_length=32,verbose_name='权限组名称')
    menu=models.ForeignKey(to='Menu',on_delete=True)
class Menu(models.Model):
    '''
    菜单表
    '''
    title=models.CharField(max_length=32)

权限系统需要在django项目settings.py 中设置如下

PERMISSION_DICT_SESSION_KEY='user_permission_dict_key'   #权限字典存入session中
PERMISSION_MENU_SESSION_KEY='user_permission_menu_key'   #权限目录放入session中
REX_FORMAT = "^%s$"                        #url的匹配头部和结尾设置
VALID_LIST = [                             #url的访问白名单
    '/crm/login/',
    '^/admin/.*',
]

权限系统的app中建立services包,init_permission.py 文件 把权限的url存入session中,把权限的目录存入session中

from  django.conf import settings
def init_permission(user,request):
    '''
    登录用户的权限初始化
    :param user:登录用户对象
    :param request:
    :return:
    '''
    permisssions_list = user.roles.filter(permissions__id__isnull=False).values(
        'permissions__id',#权限id
        'permissions__title',#权限名称
        'permissions__url',#权限url
        'permissions__code',#权限code
        'permissions__group__id',#权限组id
        'permissions__group_menu__id',#是否为组内菜单
        'permissions__group__menu__id',#一级菜单id
        'permissions__group__menu__title',#一级菜单名称
    ).distinct()
    #获取权限信息+菜单放入session 中,以后生成动态菜单
    permission_menu_list=[]
    for item in permisssions_list:
        val={
            'id':item['permissions__id'],
            'title':item['permissions__title'],
            'url':item['permissions__url'],
            'pid':item['permissions__group_menu__id'],
            'menu_id':item['permissions__group__menu__id'],
            'menu_name':item['permissions__group__menu__title'],
        }
        permission_menu_list.append(val)
    request.session[settings.PERMISSION_MENU_SESSION_KEY]=permission_menu_list
    #获取权限信息放入session中
    permission_dict = {}
    for permission in permisssions_list:
        group_ip = permission['permissions__group__id']
        url = permission['permissions__url']
        code = permission['permissions__code']
        if group_ip in permission_dict:
            permission_dict[group_ip]['urls'].append(url)
            permission_dict[group_ip]['codes'].append(code)
        else:
            permission_dict[group_ip] = {'urls': [url, ], 'codes': [code, ]}
    request.session[settings.PERMISSION_DICT_SESSION_KEY]=permission_dict

权限系统的app中建立templatetags包,rbac.py 文件  构造权限目录

from django.template import Library
from django.conf import settings
import re
register=Library()
@register.inclusion_tag('rbac/menu.html')
def menu(request):
    permission_menu_list = request.session[settings.PERMISSION_MENU_SESSION_KEY]
    current_url = request.path_info
    current_pxe = settings.REX_FORMAT

    # 构造二级菜单字典
    per_dict = {}
    for per_item in permission_menu_list:
        if not per_item['pid']:
            per_dict[per_item['id']] = per_item
    for item in permission_menu_list:
        if not re.match(current_pxe % (item['url']), current_url):
            continue
        if item['pid']:
            per_dict[item['pid']]['active'] = True
        else:
            item['active'] = True
    # 生成菜单字典
    menu_dict = {}
    for menu_item in per_dict.values():
        if menu_item['menu_id'] in menu_dict:
            menu_dict[menu_item['menu_id']]['children'].append(
                {'id': menu_item['id'], "title": menu_item['title'], 'url': menu_item['url'],
                 'active': menu_item.get('active', False)})
            # menu_item['menu_id']['children'].append({'id':menu_item['id'],"title":menu_item['title'],'url':menu_item['url'],'active':menu_item.get('active',False)})
            if menu_item.get('active', False):
                menu_item['menu_id']['active']: True
            # menu_item['menu_id']['children'].append({'id':menu_item['id'],"title":menu_item['title'],'url':menu_item['url'],'active':menu_item.get('active',False)})
        else:
            menu_dict[menu_item['menu_id']] = {
                'menu_name': menu_item['menu_name'],
                'active': menu_item.get('active', False),
                'children': [{'id': menu_item['id'], "title": menu_item['title'], 'url': menu_item['url'],
                              'active': menu_item.get('active', False)}]
            }
    return {'menu_dict':menu_dict}

权限系统的app中建立templates/rbac/menu.html 文件  构造权限的html页面 

{% for menu in menu_dict.values %}
                <div class="con-menu">
                    <div class="menu-name">{{ menu.menu_name }}</div>

                    <div class="menu-item">
                        {% for item  in menu.children  %}
                            {% if item.active %}
                                <a href="{{ item.url }}" class="active">{{ item.title }}</a>
                            {% else %}
                                <a href="{{ item.url }}">{{ item.title }}</a>
                            {% endif %}

                        {% endfor %}
                    </div>
                </div>
            {% endfor %}

在 要使用权限系统的app中 的布局页面,中把 menu.html 页面个包含到目录位置

{% load rbac %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body{
            margin: 0;
        }
        .pg-head{
            height: 48px;
            background-color: darkgray;
        }
        .menu{
            position: absolute;
            top:48px;
            left: 0px;
            bottom: 0px;
            width: 100px;
            background-color: whitesmoke;
        }
        .content{
            position: absolute;
            top: 48px;
            left: 100px;
            right: 0px;
            bottom: 0px;
            overflow: auto;
            background-color: aliceblue;
        }
        .con-menu .menu-name{
            background-color: beige;
        }

        .con-menu .menu-item a{
            display: block;
            margin-left: 10px;
        }
         .con-menu .menu-item a.active{
             color: aquamarine;
         }
    </style>
</head>
<body>
    <div class="pg-head">头部菜单</div>
    <div class="pg-body">
        <div class="menu">
            {% menu request %}
        </div>
        <div class="content">
                {% block content  %}
                {% endblock %}
        </div>
    </div>
</body>
</html>

 权限系统中的权限的验证时放在中间件找那个实现的

MIDDLEWARE = [
    #'django.middleware.cache.UpdateCacheMiddleware',
    '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',
    #'django.middleware.cache.FetchFromCacheMiddleware',
    'rbac.middlewares.rbac.RbacMiddleware', # 权限验证的中间件
]

权限中间件  在 rbac app 中创建 middlewares包创建rbac.py文件 在其中创建 继承中间件的类,实现用户登录权限的验证。

from django.conf import settings
from  django.shortcuts import HttpResponse
import re
class MiddlewareMixin(object):
    def __init__(self, get_response=None):
        self.get_response = get_response
        super().__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 RbacMiddleware(MiddlewareMixin):
    def process_request(self,request):
       #访问白名单
        current_url = request.path_info
        white_list=settings.VALID_LIST
        # if current_url=='/crm/login/':
        #     return None
        for valid_item in white_list:
            if re.match(valid_item,current_url):
                return None
        #获取用户的权限信息
        permission_dict=request.session.get(settings.PERMISSION_DICT_SESSION_KEY)
        #print(permission_dict)
        if not permission_dict:
            return HttpResponse('当前用户无权限信息.')
        #匹配用户是否拥有访问当前页面的权限
        flag=False
        for permission_item in permission_dict.values():
            urls=permission_item['urls']
            codes=permission_item['codes']

            for itme_url in urls:
                reg=settings.REX_FORMAT %(itme_url)
                if re.match(reg,current_url):
                    request.permission_codes = codes
                    print(request.permission_codes)
                    flag=True
                    break
            if flag:
                break
        if not flag:
            return HttpResponse('无权访问.')

 

posted @ 2018-08-30 14:49  hexintong  阅读(2702)  评论(1编辑  收藏  举报