• 权限管理之权限粒度控制


    粒度控制

    权限无非就增,删,改,查四种操作,粒度控制指的是在对每个表的管理中,根据用户的权限来显示用户可以进行的操作。

    简单的实现

    在之前的 RBAC 权限管理的基础上能够简单实现该功能。

    因为已经在 session 中存储了关于权限的 url 列表,所以在模板层的 a 标签处进行判断,如果对应的 url 在 permission_list 中时进行显示,否则不显示。

    {% if "users/add" in permissions_list%}
    <a class="btn btn-primary" href="/users/add">添加用户</a>
    {% endif %}
    

    该方法虽然简单但并不方便,因为每次判断显示与否都需要跟表挂钩。好的方法应该摆脱表控制,在任何模板中都能够方便使用。

    实现方案 2

    更改数据库结构

    实际上,可以对操作进行更细致的划分,比如,将操作作为动作字段加入到权限表中,并将权限表与权限组表关联,权限组表存储对哪类数据进行的操作。

    class Permission(models.Model):
    	title=models.CharField(max_length=32)
    	url=models.CharField(max_length=32)
    
    	action=models.CharField(max_length=32,default="")
    	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
    
    

    登录验证

    因为增加了一张表和一些字段,使得我们能用到的信息更多了。更多的信息有助于更方便的实现所需要的功能。

    更多关于权限的信息,获取到的形式都有变化:

    permissions = user.roles.all().values("permissions__url","permissions__group_id","permissions__action").distinct()
    

    permissions 的形式:

    permissions:
    [
    
    	{'permissions__url': '/users/add/', 
    	'permissions__group_id': 1, 
    	'permissions__action': 'add'}, 
    
    	{'permissions__url': '/roles/', 
    	'permissions__group_id': 2, 
    	'permissions__action': 'list'}, 
    
    	{'permissions__url': '/users/delete/(\d+)', 
    	'permissions__group_id': 1, 
    	'permissions__action': 'delete'}, 
    
    	{'permissions__url': 'users/edit/(\d+)', 
    	'permissions__group_id': 1, 
    	'permissions__action': 'edit'}
     ]
    

    之前所实现的过程中使用的是权限列表 permission_list ,其中只能存储权限 url ,现在能获取更多的信息了,自然,注册到 session 中的有关权限的信息也可以以更方便的形式来存贮:

    permission_dict
    
     
     {
    
     1: {
     'urls': ['/users/', '/users/add/', '/users/delete/(\d+)', 'users/edit/(\d+)'], 
     'actions': ['list', 'add', 'delete', 'edit']}, 
    
     2: {
     'urls': ['/roles/'],
     'actions': ['list']}
    
     }
    

    将从数据库中取出的权限数据转成我们想要形式的代码如下:

    # 以字典的形式存储动作信息,此种方式能够存储更多内容
    permission_dict = {}
    for item in permissions:
    	gid = item.get('permissions__group_id')
    
    	# 以group id为键,如果是第一次则赋值,其他则添加
    	if not gid in permission_dict:
    		permission_dict[gid] = {
    			"urls": [item["permissions__url"], ],
    			"actions": [item["permissions__action"], ]
    		}
    
    	else:
    		permission_dict[gid]["urls"].append(item["permissions__url"])
    		permission_dict[gid]["actions"].append(item["permissions__action"])
    
    request.session["permission_dict"] = permission_dict
    

    中间件权限校验

    进行权限校验时,从在 session 注册的字典中找到相关url信息进行校验并将权限允许的动作存到request中,方便在视图层的使用。

    permission_dict = request.session.get("permission_dict")
    
    # 从字典中找到相关url信息进行校验并将权限允许的动作存到request中方便以后使用
    for permission in permission_dict.values():
    	urls = permission['urls']
    	for reg in urls:
    		reg = "^%s$"%reg
    		ret = re.match(reg, current_path)
    
    		# 如果匹配到权限路径,将相关的动作存储到session中
    		if ret:
    			request.actions = permission["actions"]
    			return None
    
    	return HttpResponse("没有访问权限!")
    

    视图层和模板层的收尾工作

    在 request 中存储了用户能够进行的操作动作之后,在模板层可以这么使用:

    {% if "add" in actions%}
    <a class="btn btn-primary" href="/users/add">添加用户</a>
    {% endif %}
    

    为了方便,可以将所有的类似 if "action" in actions 的判断封装到一个类中,方便调用。

    class Per(object):
        def __init__(self, actions):
            self.actions = actions
    
        def add(self):
            return "add" in self.actions
    
        def delete(self):
            return "delete" in self.actions
    
        def edit(self):
            return "edit" in self.actions
    
        def list(self):
            return "list" in self.actions
    

    视图层代码:

    def users(request):
    
        users_list = models.User.objects.all()
        id = request.session.get("user_id")
        user = models.User.objects.filter(id=id).first()
        permission_list = request.session.get("permission_list")
        # actions = request.session.get("actions")
        per = Per(request.actions)
    
        return render(request, "users.html", locals())
    

    模板层代码:

    {% extends 'base.html' %}
    
    {% block con %}
        <h4>用户列表</h4>
        {% if per.add %}
        <a class="btn btn-primary" href="/users/add">添加用户</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 users_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 class="btn btn-danger" href="/users/delete/{{ user.pk }}">删除</a>
            {% endif %}
            {% if per.edit %}
            <a class="btn btn-warning" href="/users/edit/{{ user.pk }}">编辑</a>
            {% endif %}
    
        </td>
        </tr>
        {% endfor %}
    
        </tbody>
        </table>
    {% endblock %}
    

    不同用户登录下不同权限显示不同:

    1540560182058

    1540560232231

    GitHub 地址:https://github.com/protea-ban/oldboy/tree/master/9day83/rbacDemo

  • 相关阅读:
    Python学习第15天_模块
    Python学习第14天_文件读取写入
    Python学习第13天_练习(图书馆的创建)
    Python学习第12天_类
    Python学习第11天_参数
    Python学习第10天_函数
    Python学习第九天_模块的应用
    Android Bluetooth HIDL服务分析
    Mac下CLion配置Google GTest小结
    MacOS通过homebrew安装老版本的软件
  • 原文地址:https://www.cnblogs.com/banshaohuan/p/9858840.html
Copyright © 2020-2023  润新知