侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

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

框架(架构)  /  管理员 发布于 7年前   141

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.pyfrom django.db import modelsclass 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.captionclass 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.usernameclass 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.titleclass 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 refrom django.shortcuts import render,redirect,HttpResponsefrom django.conf import settingsclass 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 responseclass 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 refrom django.template import Libraryregister = 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="https:/article/{{ child.permission_url }}" rel="external nofollow" rel="external nofollow" >{{ child.permission__title }}</a></li>    {% else %}      <li class="menu_second"><a href="https:/article/{{ 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="https:/article/{% static 'rbac/bootstrap-3.3.7/css/bootstrap.min.css' %}" rel="external nofollow" >  <link rel="stylesheet" href="https:/article/{% 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实例讲解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。


  • 上一条:
    详解一种用django_cache实现分布式锁的方式
    下一条:
    Django之PopUp的具体实现方法
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • Filament v3.1版本发布(0个评论)
    • docker + gitea搭建一个git服务器流程步骤(0个评论)
    • websocket的三种架构方式使用优缺点浅析(0个评论)
    • ubuntu20.4系统中宿主机安装nginx服务,docker容器中安装php8.2实现运行laravel10框架网站(0个评论)
    • phpstudy_pro(小皮面板)中安装最新php8.2.9版本流程步骤(0个评论)
    • 近期文章
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2018-05
    • 2020-02
    • 2020-03
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-11
    • 2021-03
    • 2021-09
    • 2021-10
    • 2021-11
    • 2022-01
    • 2022-02
    • 2022-03
    • 2022-08
    • 2023-08
    • 2023-10
    • 2023-12
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客