权限管理之权限粒度控制

粒度控制

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

简单的实现

在之前的 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

posted @ 2018-10-26 21:28  banshaohuan  阅读(2321)  评论(0编辑  收藏  举报