基于Django实现RBAC权限管理

本文介绍了基于Django实现RBAC权限管理的方法,包括设计表关系、权限初始化和验证、菜单显示、自定义标签以及权限后台管理的详细步骤。通过用户、角色、权限和菜单的关联,实现权限控制,确保用户只能访问其角色允许的菜单和URL。
摘要由CSDN通过智能技术生成

概述

RBAC(Role-Based Access Control,基于角色的访问控制),通过角色绑定权限,然后给用户划分角色。在web应用中,可以将权限理解为url,一个权限对应一个url。

在实际应用中,url是依附在菜单下的,比如一个简单的生产企业管理系统,菜单可以大致分为以下几块:制造、资材、生产管理、人事、财务等等。每个菜单下又可以有子菜单,但最终都会指向一个url,点击这个url,通过Django路由系统执行一个视图函数,来完成某种操作。这里,制造部的员工登录系统后,肯定不能点击财务下的菜单,甚至都不会显示财务的菜单。

设计表关系

基于上述分析,在设计表关系时,起码要有4张表:用户,角色,权限,菜单:

  • 用户可以绑定多个角色,从而实现灵活的权限组合 :用户和角色,多对多关系
  • 每个角色下,绑定多个权限,一个权限也可以属于多个角色:角色和权限,多对多关系
  • 一个权限附属在一个菜单下,一个菜单下可以有多个权限:菜单和权限:多对一关系
  • 一个菜单下可能有多个子菜单,也可能有一个父菜单:菜单和菜单是自引用关系

其中角色和权限、用户和角色,是两个多对多关系,由Django自动生成另外两种关联表。因此一共会产生6张表,用来实现权限管理。

下面我们新建一个项目,并在项目下新建rbac应用,在该应用的models.py中来定义这几张表:

from django.db import models


class Menu(models.Model):
    """
    菜单
    """
    title = models.CharField(max_length=32, unique=True)
    parent = models.ForeignKey("Menu", null=True, blank=True) 
    # 定义菜单间的自引用关系
    # 权限url 在 菜单下;菜单可以有父级菜单;还要支持用户创建菜单,因此需要定义parent字段(parent_id)
    # blank=True 意味着在后台管理中填写可以为空,根菜单没有父级菜单

    def __str__(self):
        # 显示层级菜单
        title_list = [self.title]
        p = self.parent
        while p:
            title_list.insert(0, p.title)
            p = p.parent
        return '-'.join(title_list)


class Permission(models.Model):
    """
    权限
    """
    title = models.CharField(max_length=32, unique=True)
    url = models.CharField(max_length=128, unique=True)
    menu = models.ForeignKey("Menu", null=True, blank=True)

    def __str__(self):
        # 显示带菜单前缀的权限
        return '{menu}---{permission}'.format(menu=self.menu, permission=self.title)


class Role(models.Model):
    """
    角色:绑定权限
    """
    title = models.CharField(max_length=32, unique=True)

    permissions = models.ManyToManyField("Permission")
    # 定义角色和权限的多对多关系

    def __str__(self):
        return self.title


class UserInfo(models.Model):
    """
    用户:划分角色
    """
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)
    nickname = models.CharField(max_length=32)
    email = models.EmailField()

    roles = models.ManyToManyField("Role")
    # 定义用户和角色的多对多关系

    def __str__(self):
        return self.nickname

权限的初始化和验证

我们知道Http是无状态协议,那么服务端如何判断用户是否具有哪些权限呢?通过session会话管理,将请求之间需要”记住“的信息保存在session中。用户登录成功后,可以从数据库中取出该用户角色下对应的权限信息,并将这些信息写入session中。

所以每次用户的Http request过来后,服务端尝试从request.session中取出权限信息,如果为空,说明用户未登录,重定向至登录页面。否则说明已经登录(即权限信息已经写入request.session中),将用户请求的url与其权限信息进行匹配,匹配成功则允许访问,否则拦截请求。

我们先来实现第一步:提取用户权限信息,并写入session

为了实现rabc功能可在任意项目中的可用,我们单独创建一个rbac应用,以后其它项目需要权限管理时,直接拿到过,稍作配置即可。在rbac应用下新建一个文件夹service,写一个脚本init_permission.py用来执行初始化权限的操作:用户登录后,取出其权限及所属菜单信息,写入session中

from ..models import UserInfo, Menu


def init_permission(request, user_obj):
    """
    初始化用户权限, 写入session
    :param request: 
    :param user_obj: 
    :return: 
    """
    permission_item_list = user_obj.roles.values('permissions__url',
                                                 'permissions__title',
                                                 'permissions__menu_id').distinct()
    permission_url_list = []  
    # 用户权限url列表,--> 用于中间件验证用户权限
    permission_menu_list = []  
    # 用户权限url所属菜单列表 [{"title":xxx, "url":xxx, "menu_id": xxx},{},]

    for item in permission_item_list:
        permission_url_list.append(item['permissions__url'])
        if item['permissions__menu_id']:
            temp = {
  "title": item['permissions__title'],
                    "url": item["permissions__url"],
                    "menu_id": item["permissions__menu_id"]}
            permission_menu_list.append(temp)

    menu_list = list(Menu.objects.values('id', 'title', 'parent_id'))
    # 注:session在存储时,会先对数据进行序列化,因此对于Queryset对象写入session,加list()转为可序列化对象

    from django.conf import settings  
  • 20
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
RBAC(Role-Based Access Control)是一种基于角色的访问控制,它将权限授予角色,然后将角色授予用户。在Django中,可以使用django-guardian或django-rules等第三方库来实现RBAC权限管理,也可以自己编写代码实现。 下面是一个基于Django自己编写的简单RBAC权限管理系统的实现过程: 1. 定义权限模型 在Django中,可以通过定义模型来表示权限。例如,可以定义一个Permission模型,用来表示系统中的所有权限: ``` from django.db import models class Permission(models.Model): name = models.CharField(max_length=255, unique=True) codename = models.CharField(max_length=100, unique=True) ``` 其中name字段表示权限的名称,codename字段表示权限的代码名称。 2. 定义角色模型 同样地,可以定义一个Role模型,用来表示系统中的所有角色: ``` from django.db import models class Role(models.Model): name = models.CharField(max_length=255, unique=True) permissions = models.ManyToManyField('Permission') ``` 其中name字段表示角色的名称,permissions字段表示角色拥有的权限。 3. 定义用户模型 可以使用Django自带的User模型或者自己定义一个用户模型。在用户模型中,可以添加一个roles字段,用来表示用户所拥有的角色: ``` from django.contrib.auth.models import AbstractUser from django.db import models class User(AbstractUser): roles = models.ManyToManyField('Role') ``` 4. 编写权限检查装饰器 在Django中,可以使用装饰器来检查用户是否拥有某个权限。下面是一个简单的权限检查装饰器的实现: ``` from functools import wraps from django.http import HttpResponseForbidden def permission_required(perm): def decorator(view_func): @wraps(view_func) def _wrapped_view(request, *args, **kwargs): if not request.user.has_perm(perm): return HttpResponseForbidden() return view_func(request, *args, **kwargs) return _wrapped_view return decorator ``` 在上面的代码中,permission_required装饰器接受一个权限codename作为参数,返回一个装饰器函数。这个装饰器函数接受一个视图函数作为参数,返回一个新的视图函数。新的视图函数在执行前会检查用户是否拥有该权限,如果没有则返回403禁止访问状态码。 5. 在视图函数中使用权限检查装饰器 在需要进行权限检查的视图函数上加上permission_required装饰器即可: ``` @permission_required('app.view_model') def my_view(request): # do something ``` 在上面的代码中,my_view函数需要拥有view_model权限才能访问。 6. 编写角色管理视图 可以编写一个简单的角色管理视图,用来管理系统中的角色和权限: ``` from django.shortcuts import render from .models import Role, Permission def role_list(request): roles = Role.objects.all() return render(request, 'role_list.html', {'roles': roles}) def role_detail(request, role_id): role = Role.objects.get(id=role_id) permissions = Permission.objects.all() return render(request, 'role_detail.html', {'role': role, 'permissions': permissions}) ``` 在上面的代码中,role_list函数返回所有角色的列表,role_detail函数返回指定角色的详细信息和所有权限的列表。 7. 编写用户角色管理视图 可以编写一个简单的用户角色管理视图,用来管理用户和角色的关联关系: ``` from django.shortcuts import render from django.contrib.auth.models import User from .models import Role def user_list(request): users = User.objects.all() return render(request, 'user_list.html', {'users': users}) def user_detail(request, user_id): user = User.objects.get(id=user_id) roles = Role.objects.all() return render(request, 'user_detail.html', {'user': user, 'roles': roles}) ``` 在上面的代码中,user_list函数返回所有用户的列表,user_detail函数返回指定用户的详细信息和所有角色的列表。 8. 编写用户角色管理视图的表单处理函数 可以编写一个简单的表单处理函数,用来处理用户和角色的关联关系: ``` from django.shortcuts import redirect from django.contrib.auth.models import User from .models import Role def assign_role(request, user_id): if request.method == 'POST': user = User.objects.get(id=user_id) role_ids = request.POST.getlist('roles') roles = Role.objects.filter(id__in=role_ids) user.roles.set(roles) return redirect('user_detail', user_id=user_id) ``` 在上面的代码中,assign_role函数接受一个用户ID作为参数,从POST请求中获取选中的角色ID,将这些角色和用户关联起来,然后重定向到用户详细信息页面。 9. 编写角色管理视图的表单处理函数 可以编写一个简单的表单处理函数,用来处理角色和权限的关联关系: ``` from django.shortcuts import redirect from .models import Role, Permission def assign_permission(request, role_id): if request.method == 'POST': role = Role.objects.get(id=role_id) permission_ids = request.POST.getlist('permissions') permissions = Permission.objects.filter(id__in=permission_ids) role.permissions.set(permissions) return redirect('role_detail', role_id=role_id) ``` 在上面的代码中,assign_permission函数接受一个角色ID作为参数,从POST请求中获取选中的权限ID,将这些权限和角色关联起来,然后重定向到角色详细信息页面。 10. 编写模板 最后,可以编写一些简单的模板来渲染上述视图函数返回的数据。 例如,可以编写role_list.html模板来渲染角色列表: ``` <ul> {% for role in roles %} <li><a href="{% url 'role_detail' role.id %}">{{ role.name }}</a></li> {% endfor %} </ul> ``` 可以编写role_detail.html模板来渲染角色详细信息和权限列表: ``` <h1>{{ role.name }}</h1> <h2>Permissions</h2> <form method="post" action="{% url 'assign_permission' role.id %}"> {% csrf_token %} {% for permission in permissions %} <label> <input type="checkbox" name="permissions" value="{{ permission.id }}" {% if permission in role.permissions.all %}checked{% endif %}> {{ permission.name }} </label> {% endfor %} <button type="submit">Save</button> </form> ``` 可以编写user_list.html模板来渲染用户列表: ``` <ul> {% for user in users %} <li><a href="{% url 'user_detail' user.id %}">{{ user.username }}</a></li> {% endfor %} </ul> ``` 可以编写user_detail.html模板来渲染用户详细信息和角色列表: ``` <h1>{{ user.username }}</h1> <h2>Roles</h2> <form method="post" action="{% url 'assign_role' user.id %}"> {% csrf_token %} {% for role in roles %} <label> <input type="checkbox" name="roles" value="{{ role.id }}" {% if role in user.roles.all %}checked{% endif %}> {{ role.name }} </label> {% endfor %} <button type="submit">Save</button> </form> ``` 至此,一个简单的RBAC权限管理系统就完成了。当然,实际应用中可能需要更复杂的权限管理需求,可以根据具体情况进行扩展。
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值