基于Django框架的权限组件rbac实例讲解

1.基于rbac的权限管理

RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联。简单地说,一个用户拥有若干角色,一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间都是多对多的关系。

简单的模型图示如下:

2.Rbac组件的基本目录结构:

3.按照写的流程,来讲解rbac组件中的各个部分,以及功能,

3.1 models数据库表设计(models.py)。

为了在前端页面实现2方面的控制,还需要引入两个表菜单menu和分组group:1.在一个页面,当前用户的权限,例如是否显示添加按钮、编辑、删除等按钮;2.左侧菜单栏的创建。所以一共是5个类,7张表,详细model请看下边代码。

models.py

# models.py

from django.db import models

class Menu(models.Model):
  '''页面中的菜单名'''
  title = models.CharField(max_length=32)

class Group(models.Model):
  '''权限url所属的组'''
  caption = models.CharField(verbose_name='组名称',max_length=32)
  menu =models.ForeignKey(verbose_name='组所属菜单',to='Menu',default=1) # 组所在的菜单

  class Meta:
    verbose_name_plural = 'Group组表'

  def __str__(self):
    return self.caption

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

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="是否是菜单")

  code = models.CharField(verbose_name='url代码',max_length=32,default=0) # 路径对应的描述名称
  group = models.ForeignKey(verbose_name='所属组',to='Group',null=True,blank=True)  # 所属组

  class Meta:
    verbose_name_plural = "权限表"

  def __str__(self):
    return self.titlemodel

3.2 service中的init_permission.py

功能:在用户登录成功的时候,在session中写入两个内容:1.拿到当前用户的权限url(code信息);2.拿到当前用户的可以做菜单的url信息。

详细代码如下:

初始化权限


def init_permission(user, request):
  '''
  前端页面调用,把当前登录用户的权限放到session中,request参数指前端传入的当前当前login请求时的request
  :param user: 当前登录用户
  :param request: 当前请求
  :return: None
  '''
  # 拿到当前用户的权限信息
  permission_url_list = user.roles.values('permissions__group_id',
                      'permissions__code',
                      'permissions__url',
                      'permissions__group__menu__id',   # 菜单需要
                      'permissions__group__menu__title',  # 菜单需要
                      'permissions__title',  # 菜单需要
                      'permissions__url',   # 菜单需要
                      'permissions__is_menu', # 菜单需要
                      ).distinct()

  # 页面显示权限相关,用到了权限的分组,
  dest_dic = {}
  for each in permission_url_list:
    if each['permissions__group_id'] in dest_dic:
      dest_dic[each['permissions__group_id']]['code'].append(each['permissions__code'])
      dest_dic[each['permissions__group_id']]['per_url'].append(each['permissions__url'])
    else:
      # 刚循环,先创建需要的结构,并把第一次的值放进去。
      dest_dic[each['permissions__group_id']] = {'code': [each['permissions__code'], ],
                            'per_url': [each['permissions__url'], ]}

  request.session['permission_url_list'] = dest_dic

  # 页面菜单相关
  # 1.去掉不做菜单的url,拿到的结果是menu_list,列表中的元素是字典
  menu_list = []
  for item_dic in permission_url_list:
    if item_dic['permissions__is_menu']:
      temp = {'menu_id':item_dic['permissions__group__menu__id'],
          'menu_title':item_dic['permissions__group__menu__title'],
          'permission__title': item_dic['permissions__title'],
          'permission_url':item_dic['permissions__url'],
          'permissions__is_menu':item_dic['permissions__is_menu'],
          'active':False,  # 用于页面是否被选中,
          }
      # temp 其实只是给key重新起名字,之前的名字太长了。。。。
      menu_list.append(temp)
  # 执行完成之后是如下的数据,用来做菜单。

  request.session['permission_menu_list'] = menu_list

3.3 中间件md

功能:1.白名单验证;

2.验证是否已经写入session,即:是否已经登录;

3.当前访问的url与当前用户的权限url进行匹配验证,并在request中写入code信息,

详细代码如下:

中间件

import re
from django.shortcuts import render,redirect,HttpResponse
from django.conf import settings

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 M1(MiddlewareMixin):
  '''
  判断用户有无此url的权限的中间件
  '''
  def process_request(self,request):
    current_url = request.path_info

    # 1.白名单验证
    valid_url = settings.VALID_URL
    for each in valid_url:
      if re.match(each, current_url):
        return None

    # 2.验证是否已经写入session,即:是否已经登录
    permission_dic = request.session.get('permission_url_list')
    if not permission_dic:
      return redirect('/login/')

    # 3.与当前访问的url与权限url进行匹配验证,并在request中写入code信息,
    flag = False
    for group_id,code_urls in permission_dic.items():
      for url in code_urls['per_url']:
        regax = '^{0}$'.format(url)
        if re.match(regax,current_url):
          flag = True
          request.permission_code_list = code_urls['code'] # 在session中增加code的信息,用于在页面判断在当前页面的权限,
          break
      if flag:
        break

    if not flag:
      return HttpResponse('无权访问')

  def process_response(self,request,response):
    return response

3.4 左侧菜单的生成templatetags目录下的rbac.py

功能;生成页面中的左侧菜单用inclusion_tag标签

运用:我们只需要在需要用到的文件中引用就可以生成这个菜单部分的内容。

需要用到的模板文件中:

{% load rbac %}

{% menu_html request %} 这部分就会变成用inclusion_tag生成的menu_html

详细代码如下:

inclusion_tag生成左侧菜单

import re

from django.template import Library

register = Library()

# inclusion_tag的结果是:把menu_html函数的返回值,放到menu_html中做渲染,生成一个渲染之后的大字符串,
# 在前端需要显示这个字符串的地方,只要调用menu_html就可以,如果有菜单需要传参数,这里是request,前端模板本来就有request,
@register.inclusion_tag('menu.html')
def menu_html(request):
  current_url = request.path_info

  # 结构化在页面显示的menu数据
  menu_list = request.session.get('permission_menu_list')

  menu_show_dic = {}
  for item in menu_list:
    # 先跟当前url进行匹配,如果当前的url在权限URl中,则需要修改当前的active,用于在前端页面的显示。
    url = item['permission_url']
    reg = '^{0}$'.format(url)
    if re.match(reg, current_url):
      print('匹配到了')
      item['active'] = True

    if item['menu_id'] in menu_show_dic:
      menu_show_dic[item['menu_id']]['children'].append(
        {'permission__title': item['permission__title'], 'permission_url': item['permission_url'],
         'active': item['active']})
      if item['active']:
        menu_show_dic[item['menu_id']]['active'] = True
    else:
      menu_show_dic[item['menu_id']] = {'menu_id': item['menu_id'],
                       'menu_title': item['menu_title'],
                       'active': False,
                       'children': [{'permission__title': item['permission__title'],
                              'permission_url': item['permission_url'],
                              'active': item['active']}, ]
                       }
      if item['active']:
        menu_show_dic[item['menu_id']]['active'] = True

  return {'menu_dic':menu_show_dic}

需要的模板文件templates下的menu.html

menu.html

# menu.html

<div class="menu">
  {% for k,menu in menu_dic.items %}
    {# 一级菜单 #}
    <div class="menu_first">{{ menu.menu_title }}</div>

    {# 二级菜单(就是一级菜单下边的内容) #}
    {% if menu.active %}
      <ul class="">
    {% else %}
      <ul class="hide">
    {% endif %}

  {% for child in menu.children %}
    {% if child.active %}
      <li class="menu_second active"><a href="{{ child.permission_url }}" rel="external nofollow" rel="external nofollow" >{{ child.permission__title }}</a></li>
    {% else %}
      <li class="menu_second"><a href="{{ child.permission_url }}" rel="external nofollow" rel="external nofollow" >{{ child.permission__title }}</a></li>
    {% endif %}
  {% endfor %}
  </ul>
  {% endfor %}
</div>

使用inclusion_tag的文件示例:

inclusion_tag的使用模板文件

# 这个是django的模板文件
{% load rbac %}

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{% block title %}模板{% endblock %}</title>
  <link rel="stylesheet" href="{% static 'rbac/bootstrap-3.3.7/css/bootstrap.min.css' %}" rel="external nofollow" >
  <link rel="stylesheet" href="{% static 'rbac/menu.css' %}" rel="external nofollow" >
  {% block css %} {% endblock css %}

</head>
<body>
<div class="container-fluid">
  <div class="row">
    <div class="col-md-2 menu">
      {% block menu %}
        {% menu_html request %}  {# 用inclusion_tag生成的menu_html #}
      {% endblock menu %}
    </div>
    <div class="col-md-9">
      {% block content %}
      content
      {% endblock %}
    </div>
  </div>
</div>

以上就是django中基于rbac实现的权限组件

这篇基于Django框架的权限组件rbac实例讲解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Django RBAC权限管理设计过程详解

    一.权限简介 1. 问:为什么程序需要权限控制? 答:生活中的权限限制,① 看灾难片电影<2012>中富人和权贵有权登上诺亚方舟,穷苦老百姓只有等着灾难的来临:② 屌丝们,有没有想过为什么那些长得漂亮身材好的姑娘在你身边不存在呢?因为有钱人和漂亮姑娘都是珍贵稀有的,稀有的人在一起玩耍和解锁各种姿势.而你,无权拥有他们,只能自己玩自己了. 程序开发时的权限控制,对于不同用户使用系统时候就应该有不同的功能,如: 普通员工 部门主管 总监 总裁 所以,只要有不同角色的人员来使用系统,那么就肯定需要权

  • 基于Django框架的权限组件rbac实例讲解

    1.基于rbac的权限管理 RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,一个角色拥有若干权限.这样,就构造成"用户-角色-权限"的授权模型.在这种模型中,用户与角色之间,角色与权限之间都是多对多的关系. 简单的模型图示如下: 2.Rbac组件的基本目录结构: 3.按照写的流程,来讲解rbac组件中的各个部分,以及功能, 3.1 models数据库表设计(models.py). 为了在

  • django框架cookie和session用法实例详解

    本文实例讲述了django框架cookie和session用法.分享给大家供大家参考,具体如下: 首先知道http协议 http协议它是无状态的协议,验证的信息不会保留 基于请求响应,短连接 cookie 指一段小信息,内部是一组组的键值对,保存在客户端 访问一个地址时,服务器生成一个cookie,由浏览器保留在本地,再次访问地址时就会携带这个cookie,一般用于用户信息的验证 cookie的设置: obj.set_cookie(key,value,...) 下面来看一个简单的例子 #设置co

  • django框架两个使用模板实例

    本文实例讲述了django框架使用模板.分享给大家供大家参考,具体如下: models.py: from django.db import models # Create your models here. class Book(models.Model): title=models.CharField(max_length=32,unique=True) price=models.DecimalField(max_digits=8,decimal_places=2,null=True) pub

  • php 人员权限管理(RBAC)实例(推荐)

    php-人员权限管理(RBAC) 权限管理可以想做vip的功能,普通用户和vip用户的功能是不一样的,大致会用到五张表:用户表.角色表.功能表,还有他们之间互相关联的表:用户与角色表.角色与功能表 我用到的五张表如下: 一. 首先写的是管理员页面 1.用下拉列表显示用户名 <div> <select id="user"> <?php require"../DBDA.class.php"; $db = new DBDA(); $sql =

  • Vue2.0基于vue-cli+webpack父子组件通信(实例讲解)

    在git命令行下,执行以下命令完成环境的搭建: 1,npm install --global vue-cli 安装vue命令行工具 2,vue init webpack vue-demo 使用vue命令生成一个webpack项目,项目名称为vue-demo 3,cd vue-demo 切入项目 4,npm install安装package.json中的所有依赖包 5,npm run dev运行项目 一.父组件向子组件传递数据 然后删除默认的Hello.vue组件,把App.vue整理成以下样子:

  • django框架用户权限中的session缓存到redis中的方法

    django框架默认将session保存到数据库中,在高并发访问无疑会影响服务器性能,因此最好将session保存到redis中避免直接从数据库中读取session数据 settings.py中配置如下: #配置redis CACHES = { 'default': { 'BACKEND': 'redis_cache.RedisCache', 'LOCATION': '127.0.0.1:6379', 'OPTIONS': { 'DB': 0, 'PASSWORD': 'abxdcfgda',

  • 基于注解的Dubbo服务配置方法(实例讲解)

    基于注解的Dubbo服务配置可以大大减少dubbo xml配置文件中的Service配置量,主要步骤如下: 一.服务提供方 1. Dubbo配置文件中增加Dubbo注解扫描 <!-- 开启dubbo注解支持 --> <!-- 扫描注解包路径,多个包用逗号分隔,不填pacakge表示扫描当前ApplicationContext中所有的类 --> <dubbo:annotation package="com.bounter" /> 2.Service实现

  • 基于Socket类以及ServerSocket类的实例讲解

    Socket类 套接字是网络连接的端点,套接字使应用可以从网络中读取数据,可以向网络中写入数据.不同计算机上的两个应用程序可以通过连接发送或接收字节流,以此达到相互通信的目的. 为了从一个应用程序向另一个应用程序发送消息,需要知道另一个应用程序中套接字的 IP 地址和端口号,在java中,套接字由java.net.Socket 表示. 要创建一个套接字,可以使用Socket类中众多构造函数中的一个.其中一个构造函数接收两个参数:主机号和端口号. public Socket (String hos

  • 基于python select.select模块通信的实例讲解

    要理解select.select模块其实主要就是要理解它的参数, 以及其三个返回值. select()方法接收并监控3个通信列表, 第一个是所有的输入的data,就是指外部发过来的数据,第2个是监控和接收所有要发出去的data(outgoing data),第3个监控错误信息在网上一直在找这个select.select的参数解释, 但实在是没有, 哎...自己硬着头皮分析了一下. readable, writable, exceptional = select.select(inputs, ou

  • 基于Java中UDP的广播形式(实例讲解)

    UDP---用户数据报协议,是一个简单的面向数据报的运输层协议.UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地 ,也不能保证数据包到达的顺序.由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快. 在Java中UDP的实现: * UDP: * 客户端: * 1.创建用于UDP通信的socket对象---DatagramSocket(用于UDP数据的发送和接收)---数据报套接字 * 2.准备数据,封装包

随机推荐