Django权限管理系统设计分析
权限管理顾名思义,其实就是角色控制权限的系统,每个用户对应一个角色,每个角色有对应的权限,比如公司会有CEO,总监,销售经理,销售员,每个人的权限都不一样,那我们给他展示的url也都不同
一、首先创建项目,再创建一个名为rbac的app
修改配置文件settings,将css以及js、img等放到static文件夹下
二、表结构设计
设计表:
创建五个类,七张表:
菜单表,权限组,权限表,用户表,角色表,
角色表和权限表是多对多的关系(一个角色可以有多个权限,一个权限可以对应多个角色)
用户表和角色表是多对多的关系(一个用户可以有多个角色,一个角色有多个用户)
models.py
from django.db import models # 菜单组 class Menu(models.Model): title = models.CharField(verbose_name='菜单组', max_length=32) class Meta: verbose_name_plural = '菜单表' def __str__(self): return self.title # 权限组 class Group(models.Model): title = models.CharField(verbose_name='权限标题', max_length=32) menu = models.ForeignKey(verbose_name='所属菜单', to='Menu', default=1) class Meta: verbose_name_plural= '权限组表' def __str__(self): return self.title # 权限表 class Permission(models.Model): title = models.CharField(verbose_name='标题', max_length=128) url = models.CharField(verbose_name='含正则表达式的URL', max_length=128) menu_gp = models.ForeignKey(verbose_name='组内权限', to='Permission', null=True, blank=True, related_name='x1') code = models.CharField(verbose_name='权限代号', max_length=32) group = models.ForeignKey(verbose_name='所属组', to='Group') class Meta: verbose_name_plural= '权限表' def __str__(self): return self.title # 用户表 class UserInfo(models.Model): username = models.CharField(verbose_name='用户名', max_length=32) password = models.CharField(verbose_name='密码',max_length=64) user_role = models.ManyToManyField(verbose_name='用户角色', to='Role', blank=True) class Meta: verbose_name_plural= '用户表' def __str__(self): return self.username # 角色表 class Role(models.Model): position = models.CharField(verbose_name='职位', max_length=32) permissions = models.ManyToManyField(verbose_name='角色权限', to='Permission', blank=True) class Meta: verbose_name_plural= '角色表' def __str__(self): return self.position
我们一般是先看到的是列表页面,在这个页面上是否显示添加,是否显示编辑,是否显示删除,都是需要判断的, 有无添加权限,有无删除权限,有无编辑权限,我们可以给每一个url一个代号,将代号取出来放在一个列表里面
dict = { '5': { 'codes': ['list', 'add', 'edit', 'del'], 'urls': ['/userinfo/', '/userinfo/add/', '/userinfo/(\\d+)/change/', '/userinfo/(\\d+)/delete/'] }, '1': { 'codes': ['list', 'add', 'edit', 'del'], 'urls': ['/order/', '/order/add/', '/order/(\\d+)/change/', '/order/(\\d+)/delete/'] } }
把这个字典存到session中当你访问页面的时候我就知道你有什么权限一个url对应一个code 多个url对应一个组.
三、通过Django-admin录入数据
先创建一个超级用户:python3 manage.py createsuperuser
用户名:root
密码:a123456
在admin.py中做如下配置:
from django.contrib import admin from . import models admin.site.register(models.Menu) admin.site.register(models.UserInfo) admin.site.register(models.Role) admin.site.register(models.Permission) admin.site.register(models.Group)
models.py中做如下配置,就可以在添加的时候显示中文了。
# 菜单组 class Menu(models.Model): title = models.CharField(verbose_name='菜单组', max_length=32) class Meta: verbose_name_plural = '菜单表' def __str__(self): return self.title
四、编写登录
利用Django的中间件进行控制,没有登录的用户不能直接访问内部的url,而且只能访问admin,login,index这三个url,将其设置为白名单,用户登录成功后,将用户信息方法哦session里边,进行权限访问时去session里边读取,如果有的话进行url跳转,如果没有的话返回‘’无权访问‘’
1.在settings内设置白名单:
2.编写中间件控制时,必须继承MiddlewareMixin这个类
# -*- coding:utf-8 -*- # !/usr/bin/python from django.shortcuts import redirect, HttpResponse from django.conf import settings import re 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 RbacMiddleware(MiddlewareMixin): def process_request(self, request): # 1.当前请求的URL current_request_url = request.path_info # 2.处理白名单 for url in settings.VALID_URL_LIST: if re.match(url, current_request_url): return None # 3.获取session中保存的权限信息 permission_dict = request.session.get(settings.XX) print(permission_dict) if not permission_dict: return redirect(settings.RBAC_LOGIN_URL) flag = False for group_id, values in permission_dict.items(): for url in values["urls"]: if re.match(url, current_request_url): flag = True break if flag: break if not flag: return HttpResponse("无权访问")