zoukankan      html  css  js  c++  java
  • Django_RBAC_demo2 升级版权限控制组件

    RBAC 升级版

     预期要求

      前端在无权限时不在提供操作标签

      更改部分硬编码

      实现更加精准的权限控制

    未改动前的版本

    在这里 ⬇

    Django_rbac_demo 权限控制组件框架模型

    具体更改

    数据库结构更改:

      对 permission 表新增两个字段 用于分类具体控制表(group)  以及当前操作行为 (action)

      增加新表 permissiongroup 用来保存控制表字段

    models.py 

    from django.db import models
    
    # Create your models here.
    
    
    class User(models.Model):
        name = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
        roles = models.ManyToManyField(to="Role")
    
        def __str__(self): return self.name
    
    
    class Role(models.Model):
        title = models.CharField(max_length=32)
        permissions = models.ManyToManyField(to="Permission")
    
        def __str__(self): return self.title
    
    
    class Permission(models.Model):
        title = models.CharField(max_length=32)
        url = models.CharField(max_length=32)
        action = models.CharField(max_length=32, default="1")
        group = models.ForeignKey("PermissionGroup", default=1)
    
        def __str__(self):return self.title
    
    
    class PermissionGroup(models.Model):
        title = models.CharField(max_length=32)
    
        def __str__(self): return self.title

    permission.py

        表结构更改后,后台可利用的数据更多。传回一个字典。

       以及需要 数据处理成便于操作的形式

    """
    为了解耦,将处理权限的代码保存在组件里面
    """
    
    
    def initial_session(user,request):
    
        """
        方案1
            不好用,只用一个权限字段实在功能有限
         已被淘汰
    """ # # 查看当前用户的所有的权限 # # 因为会有values 的原理会导致有重复需要去重 # ret = user.roles.all().values("permissions__url").distinct() # permission_list = [] # # 将所有的权限保存在一个列表里面,稍微处理下数据便于操作 # for i in ret: # permission_list.append(i["permissions__url"]) # # 把用户的用户权限保存在 session 里面 # request.session["permission_list"] = permission_list """ 方案2 """ # permission__group_id permission表 的group 字段 因为外键会后面加个 ”_id“ 别忘了啊 # 取出来当前用户的权限,每个权限对应的属性 permissions = user.roles.all().values( "permissions__url", "permissions__group_id", "permissions__action",).distinct() # 对拿到的数据进行数据处理 permission_dict = {} for i in permissions: gid = i["permissions__group_id"] if gid not in permission_dict: permission_dict[gid] = { "urls": [i["permissions__url"], ], "actions": [i["permissions__action"], ] } else: permission_dict[gid]["urls"].append(i["permissions__url"]) permission_dict[gid]["actions"].append(i["permissions__action"]) request.session["permission_dict"] = permission_dict

    rbac.py 

      对传回的数据进行权限验证

    import re
    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse, redirect
    
    """
    写在中间件里面可以完全避免每次都要重复校验的问题
    在请求来的时候进行校验,因此要写在 process_request 方法里面
    """
    
    
    class ValidPermission(MiddlewareMixin):
        def process_request(self, request):
            # 当前访问路径
            current_path = request.path_info
            """
            检查是否属于白名单
                admin 的内部流程
                    不允许一上来就访问首页,必须要跳转到 登陆页面
                    http://127.0.0.1:8000/admin/login/?next=/admin/
                    第二次跳转到登录页面的请求如果没有被定义可通过就会被拦截
                    无法只使用 admin 为过滤选项
                    不能用 in 单纯的判断,还是要用到正则处理
                    需要放过所有 admin 开头的 url
            """
            valid_url_list = ["/login/", "/reg/", "/admin/.*"]
            for valid_url in valid_url_list:
                ret = re.match(valid_url, current_path)
                if ret:
                    # 中间件 return None 表示这个中间件已经执行完毕
                    return None
    
            """
            校验是否登录
                对于没有登陆的用户返回报错应该是让他去登陆
            """
            user_id = request.session.get("user_id")
            if not user_id:
                return redirect("/login/")
    
            # """
            # 校验权限 1 permission_list
            #     在编辑,以及删除页面的时候 url 不是固定的,
            #     会有内含的参数,因此权限列表里面不能仅仅是写死的url
            #     也不能再单纯的用 in 来判断。还是要靠正则来处理
            #     将权限列表里面的权限信息用 正则表达式来保存
            #     然后对访问页面进行验证是否可以通过来处理
            # """
            # permission_list = request.session.get("permission_list",[])
            # flag = False
            # for permission in permission_list:
            #     permission = "^%s$" % permission
            #     ret = re.match(permission, current_path)
            #     if ret:
            #         flag = True
            #         break
            # if not flag:
            #     return HttpResponse("没有访问权限!")
            # return None
    
            """
            校验权限 2 permission_dict
            """
            permission_dict = request.session.get("permission_dict")
            for i in permission_dict.values():
                urls = i["urls"]
                for reg in urls:
                    reg = f"^{reg}$"
                    ret = re.match(reg, current_path)
                    if ret:
                        # 加一个自定义的 actions 属性在里面
                        request.actions = i["actions"]
                        return None
            return HttpResponse("没有访问权限!")

    views.py

       封装一个 Per 类便于前端更方便的取数据

    from django.shortcuts import render,HttpResponse
    import re
    # Create your views here.
    from rbac.models import *
    from rbac.service.perssions import *
    
    class Per():
        def __init__(self,actions):
            self.actions = actions
    
        def add(self):
            return "add" in self.actions
    
        def delete(self):
            return "del" in self.actions
    
        def edit(self):
            return "edit" in self.actions
    
        def cat(self):
            return "cat" in self.actions
    
    def users(request):
        user_list = User.objects.all()
        # permission_dict = request.session["permission_dict"]
        # 查询当前登陆人的名字
        id = request.session.get("user_id")
        user = User.objects.filter(id=id).first()
    per
    = Per(request.actions)
    return render(request, "users.html",locals()) def add_user(request): permission_list = request.session["permission_list"] return HttpResponse("add user.....") def del_user(request,id): return HttpResponse(f"del_user: {id}") def roles(request): role_list = Role.objects.all()
    per
    = Per(request.actions)
    return render(request,"roles.html",locals()) def login(request): print("login") if request.method == "POST": user = request.POST.get("user") pwd = request.POST.get("pwd") # 拿到当前用户对象 user = User.objects.filter(name=user, pwd=pwd).first() if user: # 把用户的id 保存在 session 里面 request.session["user_id"] = user.pk # 查询当前用户的所有的权限 initial_session(user, request) return HttpResponse("登录成功!") return render(request, "login.html",locals())

     users.html 

       前端页面基于 per 对象的 actions 控制才判断是否对标签进行显示

    {% extends "base.html" %}
    {% block con %}
        <h4>用户列表</h4>
    
        {% if per.add %}
        <a href="/users/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.name }}</td>
                    <td>
                        {% for role in user.roles.all %}
                            {{ role.title }}
                        {% endfor %}
                    </td>
                    <td>
                        {% if per.delete%}
                         <a href="/users/delete/{{ user.pk }}/" class="btn btn-danger">删除</a>
                        {% endif %}
    
                        {% if per.edit %}
                        <a href="" class="btn btn-warning">编辑</a>
                        {% endif %}
    
                    </td>
                </tr>
            {% endfor %}
            </tbody>
        </table>
    {% endblock %}
  • 相关阅读:
    0713学期末了
    Oracle Redo日志的状态
    crontab调用shell访问sqlplus失败原因
    Solaris下批量杀进程
    oracle用户管理的完全恢复4:在ARCHIVELOG 模式(恢复打开的数据库)
    oracle用户管理的完全恢复3:在ARCHIVELOG 模式(恢复关闭的数据库)
    shell删除所有空行(忽略编码格式)
    oracle用户管理的完全恢复1:在NOARCHIVELOG 模式下执行恢复
    查看oracle用户权限
    OLTP与OLAP介绍
  • 原文地址:https://www.cnblogs.com/shijieli/p/10184948.html
Copyright © 2011-2022 走看看