基于角色的权限控制系统(role-based access control)
Posted silence_cho
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于角色的权限控制系统(role-based access control)相关的知识,希望对你有一定的参考价值。
role-based access control(rbac),指对于不同角色的用户,拥有不同的权限 。用户对应一个角色,一个角色拥有若干权限,形成用户-角色-权限的关系,如下图所示。当一个用户进行访问数据时,根据其角色判断其拥有的权限,限定其操作。通过django实现一个简单的rbac app,简要记录下过程。
1.实现效果
实现效果如下图所示,不同用户拥有不同角色,不同角色拥有不同权限。下图中只是对角色和用户两张表进行编辑和访问,当我们项目中还有其他数据需要进行权限控制访问时,只需进行两处设置,一是在权限表中为这个数据表增加 "增删改查" 四个权限,然后将对应权限添加到角色表中即可。
2. 实现过程
2.1 数据库设计
建立四张表,用户表,角色表,权限表和权限组表。models.py代码如下:
from __future__ import unicode_literals from django.db import models class User(models.Model): name = models.CharField(max_length=32) password = models.CharField(max_length=16) age = models.IntegerField() role = models.ForeignKey(to=\'Role\') def __str__(self): return self.name class Role(models.Model): title = models.CharField(max_length=32) permission = 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) group = models.ForeignKey(to=\'PermissionGroup\') def __str__(self): return self.title class PermissionGroup(models.Model): title = models.CharField(max_length=32) def __str__(self): return self.title
这里一条权限实际上对应一条url,表示对一张数据表的一个操作(增删改查),而权限分组则表明权限属于对那张表的操作。因此有几张可以操作的数据表应对应几个权限组,而每个权限组,应该都包括四个权限:增删改查。一条权限的数据信息如下图。这里只有用户表和角色表两张表可以操作,对应用户管理和角色管理两个权限组。
2.2 权限控制
用户是通过url来访问数据,而一条url对应一个权限。因此当用户访问数据时,权限控制的流程是:
a, 首先判断用户是否登录,未登录时重定向至登陆页面。
b,用户登陆进来时,根据其角色判断拥有的所有权限,并将其权限表计入session中。
c,用户登陆后,当其访问数据时,根据session中权限表判断,若无查看权限则直接拒绝,否则允许查看,进一步判断增删改权限来个性化前端显示页面。
url代码如下:
# 总的一级路由
from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r\'^admin/\', admin.site.urls), url(r\'\',include(\'rbac.urls\')) ] # rbac.urls代码,二级分发路由 urlpatterns = [
url(r\'^login/$\', views.login), url(r\'^user/$\', views.listUser), url(r\'^user/add/\', views.addUser), url(r\'^user/edit/(\\d+)\', views.editUser), url(r\'^user/delete/(\\d+)\', views.deleteUser), url(r\'^role/$\', views.listRole), url(r\'^role/add/\', views.addRole), url(r\'^role/edit/(\\d+)\', views.editRole), url(r\'^role/delete/(\\d+)\', views.deleteRole), ]
url权限的判断,通过自定义中间件来实现,将用户访问的url和其权限表url匹配,拥有权限时才允许通过,交给相应的视图函数处理。代码如下:
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse,redirect import re #自定义中间件 class ValidPermission(MiddlewareMixin): def process_request(self,request): current_path = request.path # 拿到当前请求路径 \'/user/\'
#设置白名单,允许任何人访问的url valid_urls = [\'/login/\',\'/admin/(.*)\'] for url in valid_urls: path = \'^%s$\'%url ret = re.match(path, current_path) if ret: return None #对于没有登陆的用户重定向至登陆页面 user_id = request.session.get(\'user\',[]) if not user_id: return redirect(\'/login/\') #根据权限来匹配url,决定当前用户是否有访问权限 permission_list = request.session[\'permission_list\'] # print permission_list,current_path for permission in permission_list.values(): urls = permission[\'permission__url\'] for url in urls: path = \'^%s$\'%url ret = re.match(path,current_path) if ret: request.actions = permission[\'permission__action\'] #[u\'list\', u\'edit\', u\'add\'] # print request.actions return None return HttpResponse(\'没有访问权限\')
登陆函数代码:
def login(request): if request.method==\'POST\': name = request.POST.get(\'name\') passsword = request.POST.get(\'password\') # print name, passsword user_obj = models.User.objects.filter(name=name,password=passsword).first() if user_obj: request.session[\'user\']=user_obj.pk initial_permission(request,user_obj) return redirect(\'/user/\') else: return render(request,\'login.html\') return render(request, \'login.html\') from rbac import models def initial_permission(request,user): permissions = models.Role.objects.filter(user=user).values(\'permission__url\',\'permission__action\',\'permission__group_id\').distinct() permission_list = {} for item in permissions: if item[\'permission__group_id\'] not in permission_list: permission_list[item[\'permission__group_id\']]= {\'permission__url\':[item[\'permission__url\'],],\'permission__action\':[item[\'permission__action\'],]} else: permission_list[item[\'permission__group_id\']][\'permission__url\'].append(item[\'permission__url\']) permission_list[item[\'permission__group_id\']][\'permission__action\'].append(item[\'permission__action\']) #print permission_list request.session[\'permission_list\'] = permission_list # 按用户组权限id分组,得到如下的数据结构,即对两张表分别的操作权限 # {1: {\'permission__url\': [u\'/user/\', u\'/user/edit/(\\\\d+)\', u\'/user/add/\'], # \'permission__action\': [u\'list\', u\'edit\', u\'add\']}, # 2: {\'permission__url\': [u\'/role/\'], \'permission__action\': [u\'list\']}} #设置菜单的显示权限数据 menu_permissions = models.Role.objects.filter(user=user).values(\'permission__url\',\'permission__action\',\'permission__group__title\').distinct() menu_permission_list=[] for item in menu_permissions: if item[\'permission__action\'] == \'list\': menu_permission_list.append((item[\'permission__url\'],item[\'permission__group__title\'])) request.session[\'menu_permission_list\'] = menu_permission_list # print menu_permission_list
视图函数的处理主要时将数据和用户权限传给前端,前端根据权限来显示不同的页面(若用户拥有添加,删除,编辑权限,则显示增加,删除,编辑按钮,否则不显示),下面是查看用户表的视图函数和前端页面:
class PermissionAction(object): def __init__(self,actions): self.actions = actions def add_check(self): return \'add\' in self.actions def edit_check(self): return \'edit\' in self.actions def delete_check(self): return \'delete\' in self.actions # 查看用户表的视图函数 def listUser(request): users = models.User.objects.all() user_id = request.session.get(\'user\') user = models.User.objects.filter(id=user_id).first() permission_action = PermissionAction(request.actions) return render(request, \'rbac/listUser.html\', locals())
listUser.html
{% extends \'rbac/base.html\' %} {% block data_table %} <div> {% if permission_action.add_check %} <a href="/user/add/"> <button class="btn btn-success" style="margin-bottom: 15px">添加用户</button> </a> {% endif %} </div> <table class="table table-bordered "> <thead> <tr> <th>用户名</th> <th>角色</th> <th>操作</th> </tr> </thead> <tbody> {% for user in users %} <tr> <td>{{ user.name }}</td> <td>{{ user.role }}</td> <td> {% if permission_action.edit_check %} <a href="/user/edit/{{ user.pk }}"> <button class="btn btn-success">编辑</button> </a> {% endif %} {% if permission_action.delete_check %} <a href="/user/delete/{{ user.pk }}"> <button class="btn btn-danger" style="margin-left:15px">删除</button> </a> {% endif %} </td> </tr> {% endfor %} </tbody> </table> {% endblock %}
完整代码见github:https://github.com/silence-cho/Rbac
以上是关于基于角色的权限控制系统(role-based access control)的主要内容,如果未能解决你的问题,请参考以下文章
RBAC: 基于角色的访问控制(Role-Based Access Control)
关于RBAC(Role-Base Access Control)的理解(转)
简述RBAC基于角色的访问控制系统(Role-Based Access Control)