zoukankan      html  css  js  c++  java
  • Django的Rbac介绍1

    1、django的权限管理叫做RBAC

    我们在百度上查看RBAC的概念如下

    基于角色的权限访问控制(Role-Based Access Control)作为传统访问控制(自主访问,强制访问)的有前景的代替受到广泛的关注。在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。在一个组织中,角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色。角色可依新的需求和系统的合并而赋予新的权限,而权限也可根据需要而从某角色中回收。角色与角色的关系可以建立起来以囊括更广泛的客观情况。

    2、下面我们先来看下django的rbac该如何设计

    首先我们要设计三张表,表1为用户表,表2为角色表,表3为权限表,用户表关联角色表,角色表关联权限表,用户属于某个角色,而某个角色可以包含一些权限,同样一个用户可以属于多个角色,而一个角色同样可以包含多个权限,下面我们看下我们的model中的设计

    from django.db import models
    
    # Create your models here.
    
    class Userinfo(models.Model):
        username = models.CharField(max_length=64)
        uerpwd = models.CharField(max_length=64)
        roles = models.ManyToManyField(to="Role")
    
        def __str__(self):
            return self.username
        class Meta:
            verbose_name = "用户表"
            verbose_name_plural = verbose_name
    
    class Role(models.Model):
        title = models.CharField(max_length=64)
        pers = models.ManyToManyField(to="per")
    
    
        def __str__(self):
            return self.title
        class Meta:
            verbose_name="角色表"
            verbose_name_plural = verbose_name
    
    class per(models.Model):
        title = models.CharField(max_length=64)
        url = models.CharField(max_length=128)
    
        def __str__(self):
            return self.title
        class Meta:
            verbose_name = "权限表"
    

      

    设计好表结构后,我们先往表中写数据,我们先看用户表中的数据

    我们点开看下具体某个用户的角色信息

    我们可以看到,用户test1有2个角色,角色1是CEO,角色2是销售角色

    然后我们在看角色表

     我们在看下某个角色具体的权限,我们这里定义权限就是操作库的权限,比如增删改查四个权限

     我们可以看到CEO有4个权限,分别是增删改查4个权限

    最后我们在看下权限表,通过权限表,我们就可以看到一共有4个权限

    我们看下具体的权限的表内容,我们可以看到具体的权限就是一条url

     从上面的数据库的设计,我们可以知道,控制url的访问就是控制权限

     3、最后我们进入具体的代码的逻辑控制

    我们思路是这样的,因为从上面我们可以看到,如果某个用户没有某个权限,那么我们就控制这个用户是否能访问这条url就可以了,那么我们怎么做呢?

    思路1、可以写在视图函数中

    思路2、可以写在视图函数的装饰器中

    思路3、可以写在中间件中

    我们可以考虑一下,哪种最好呢?当然是第三种最好,因为每个请求都会发一个request,如果这个用户没有这个方位这个url的权限,那么我们直接在中间件就把这个请求拦截就可以了,不需要让这个请求在往后走,占用我们的资源,您说对吗?

    那么下面就看下具体的代码

    用户首先要登陆,那么登陆后,我们就需要把用户信息存储到session中,同样,我们也需要从数据库中获取我这个用户的权限信息,然后存储到session中,以后我们就可以从session拿到我这次访问的用户和我这个用户所拥有的权限,以后我们中间件函数就从session中获取这次访问的用户信息

    视图函数中的代码如下

    def login(request):
        if request.method == "GET":
            return render(request, "rbac_login.html")
        else:
            name = request.POST.get("name")
            pwd = request.POST.get("pwd")
    
            if rbacmodels.Userinfo.objects.filter(username=name,uerpwd=pwd).exists():
                userobj = rbacmodels.Userinfo.objects.get(username=name)
    
                request.session["userid"] = userobj.id
    
                # print(userobj.roles.all())
                obj = userobj.roles.all().values_list("pers__url").distinct()
                per_list = []
                for i in obj:
                    per_list.append(i[0])
                request.session["per_list"] = per_list
                print(per_list)
                # request.session.flush()
                # print(dir(request.session))
                # print("=" * 120)
                return redirect("/user/")
            else:
                return render(request, "rbac_login.html")
    

      

    下面我们在看下中间件函数是怎么实现的

    我们首先要搞一个白名单,如果url在这个白名单里,则可以直接访问,不用走后面的控制逻辑,因为比如login这类的url,你必须要放通他,如果你连login函数也拦截了,那么可以都无法登陆了

    其次我们还要搞一个判断用户是否登陆的判断,如果客户没有登陆,则让他返回到登陆界面

    最后,我们在写权限的控制逻辑,判断当前访问的url是否在权限列表中,如果在则通过,如果不在,则直接retrun回去,就达到了权限控制的需求了

    from django.utils.deprecation import MiddlewareMixin
    import re
    from django.shortcuts import HttpResponse
    from django.shortcuts import redirect
    from django.shortcuts import reverse
    
    class My_rbac_mid(MiddlewareMixin):
    
        def process_request(self,request):
            current_path = request.path_info
    
    
            # 校验白名单
    
            white_list = ["/login/","/admin/.*"]
            for wh in white_list:
                wh = "^" + wh + "$"
                res = re.match(wh,current_path)
                if res:
                    return None
    
            # 校验登陆
            if request.session.get("userid"):
                pass
            else:
                return redirect("/login/")
    
    
            # 校验权限
            per_list = request.session.get("per_list",[])
            flag = False
            if per_list:
                for per in per_list:
                    if flag == False:
                        obj = "^" + per + "$"
                        res = re.match(obj,current_path)
                        if res:
                            flag = True
                            break
                        else:
                            continue
            if flag == False:
                return HttpResponse("无权限访问")
    

      

    4、最后我们看下html代码是如何渲染的,我们的目的是如果该用户没有这个权限,则连按钮都不让他看到

    {% extends 'rbac_base.html' %}
    
    
    {% block con %}
    
        <h4>用户列表</h4>
    
        {% if "/user/add/" in per_list %}
            <a href="/user/add/" class="btn btn-primary">添加用户</a>
        {% endif %}
    
    
        <table class="table table-bordered table-striped">
            <thead>
                  <tr>
                       <th>序号</th>
                       <th>姓名</th>
                       <th>角色</th>
                       <th>操作</th>
                  </tr>
            </thead>
           <tbody>
                {% for user in user_list %}
                <tr>
                     <td>{{ forloop.counter }}</td>
                     <td>{{ user.username }}</td>
                     <td>
                         {% for role in user.roles.all %}
                            {% if forloop.last %}
                                {{ role.title }}
                             {% else %}
                                {{ role.title }}|
                             {% endif %}
                         {% endfor %}
    
                     </td>
    
                     <td>
                         {%  if "/user/del/(d+)" in per_list %}
                            <a href="/user/del/{{ user.id }}"><button type="button" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span>&nbsp删除</button></a>
                         {% endif %}
    
                        {%  if "/user/edit/(d+)" in per_list %}
                            <a href="/user/edit/{{ user.id }}"><button type="button" class="btn btn-success"><span class="glyphicon glyphicon-pencil"></span>&nbsp编辑</button></a>
                        {% endif %}
                     </td>
                </tr>
                {% endfor %}
    
           </tbody>
        </table>
    
    
    {% endblock %}
    

      

    我将逻辑控制的地方截图出来,大家重点看下

    如果有增加权限,则显示增加按钮

     如果有删除权限,则显示删除按钮

     如果有 编辑权限,则显示i编辑按钮

  • 相关阅读:
    微软 PowerShell Script Explorer
    MVC, MVP, MVVM比较以及区别(上)
    MVC中使用Unity Ioc Container
    java实现电脑远程控制完整源代码(转)
    强大的Mockito测试框架(转)
    File中操作路径的API(转)
    java如何把char型数据转换成int型数据(转)
    Test class should have exactly one public zero-argument constructor
    tomcat的webappclassloader中一个奇怪的异常信息
    在asp.net mvc中使用PartialView返回部分HTML段
  • 原文地址:https://www.cnblogs.com/bainianminguo/p/10010160.html
Copyright © 2011-2022 走看看