基于角色的权限管理

权限组件

在我们写项目时,可能会遇到给不同的用户分配不同的权限的情况,那么什么是权限呢?权限其实就是一个url

不同的url代表不同的功能,限定用户能访问的url,就给了用户不同的权限

权限管理在很多项目中都有用到,所以我们可以讲权限管理的逻辑写成一个组件

使它在不同的项目中只要经过一定的修改就能使用

创建项目

在一个项目中可以包含多个组件,同样一个组件也可以用于多个项目,这里我们想创建一个项目

然后创建两个app,一个app01写项目的主逻辑,一个rbac(Role-Based Access Control)写权限相关的逻辑

建表

我们首先能想到的是用户和权限表,一个用户可以有多个权限,而一个权限也可以对应多个用户,这样他们就是多对多的关系

但是这样的话,我们会发现一个问题,比如一个公司有很多销售员,这些销售员都有同样的权限,这时我们就需要添加很多重复的信息

这里我们可以再添加一张角色表,让角色和用户、权限都有多对多的关系

这样有新的用户后,只要给该用户分配一个角色就行了,而该角色又拥有相应的权限,就不需要再添加重复的信息了

rbac.models

from django.db import models

# Create your models here.

class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32, default=123)
    email = models.EmailField()
    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):
    url = models.CharField(max_length=32)
    title = models.CharField(max_length=32)
def __str__(self):
        return self.title

表建好后我们就要往表中添加数据了,这里我们可以先用admin添加一些基本数据

rbac.admin

from django.contrib import admin
from .models import *
# Register your models here.

admin.site.register(UserInfo)
admin.site.register(Role)

class PermissionConfig(admin.ModelAdmin):
    list_display = ["id", "title", "url"]
    ordering = ["id"]
admin.site.register(Permission, PermissionConfig)

一般情况下,我们添加一条数据会看到一个数据对象,如果想要展示具体的id,title等属性,我们可以使用上面的方法,创建一个新的类继承(admin.ModelAdmin),在里面定义list_display,讲想要看到的内容写入列表,然后使用admin.site.register(Permission, PermissionConfig),这样我们就可以在页面上看到如下效果

这里我们添加了8个权限,我们可以发现这8个权限可以分为两组,前4个是和用户有关的,而后4个是和订单有关的

这里我们可以再创建一张权限组的表,使他和权限表一对多关联,同时给权限表再创建一个编号

rbac.models

from django.db import models

# Create your models here.

class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32, default=123)
    email = models.EmailField()
    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):
    url = models.CharField(max_length=32)
    title = models.CharField(max_length=32)
    permission_group = models.ForeignKey("PermissionGroup", default=1)
    code = models.CharField(max_length=32, default="")

    def __str__(self):
        return self.title

class PermissionGroup(models.Model):
    caption = models.CharField(max_length=32)

    def __str__(self):
        return self.caption

rbac.admin

from django.contrib import admin
from .models import *
# Register your models here.

admin.site.register(UserInfo)
admin.site.register(Role)
admin.site.register(PermissionGroup)

class PermissionConfig(admin.ModelAdmin):
    list_display = ["id", "title", "url", "permission_group", "code"]
    ordering = ["id"]
admin.site.register(Permission, PermissionConfig)

最后添加的权限如下

用户登录

 urls

from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r‘^admin/‘, admin.site.urls),
    url(r‘^login/‘, views.login),
    url(r‘^users/‘, views.users),
    url(r‘^orders/‘, views.orders),
    url(r‘^orders/add/‘, views.orders_add),
]

这里我们为一些相关权限也设置了url

视图函数

由于这些是关于项目的逻辑,所以视图函数写在app01.views

from django.shortcuts import render, redirect, HttpResponse
from rbac import models
# Create your views here.

def login(request):
    if request.method == "GET":
        return render(request, "login.html")
    else:
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        user = models.UserInfo.objects.filter(name=user, pwd=pwd).first()
        if user:
            # 验证成功之后
            request.session["user_id"] = user.pk
            # 当前登录用户的所有权限
            from rbac.service.initial import initial_session
            initial_session(request, user)
            return HttpResponse("登录成功")
        else:
            return redirect("/login/")

def users(request):

    return HttpResponse("用户列表")

def orders(request):
    permission_dict = request.session.get("permission_dict")
    return render(request, "orders.html", locals())

def orders_add(request):

    return HttpResponse("添加订单")

login.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>登录</title>
</head>
<body>

<form action="/login/" method="post">
    {% csrf_token %}
    <p>用户名 <input type="text" name="user"></p>
    <p>密码 <input type="password" name="pwd"></p>
    <input type="submit" value="提交">

</form>
</body>
</html>

可以看到当用户登录以后我们先验证账号密码是否正确,然后写session,这里我们调用了rbac内的方法

from rbac.service.initial import initial_session
initial_session(request, user)

这个方法究竟做了什么呢

def initial_session(request, user):
    # 方式1
    # permission_info = user.roles.all().values("permissions__url", "permissions__title").distinct()
    # temp = []
    # for i in permission_info:
    #     temp.append(i["permissions__url"])
    # request.session["permission_list"] = temp
    # 方式2
    # 创建一个数据格式:包含所有权限,权限所在组,权限的编号
    permission_info = user.roles.all().values("permissions__url", "permissions__code", "permissions__permission_group_id").distinct()

    permission_dict = {}
    for permission in permission_info:
        if permission["permissions__permission_group_id"] in permission_dict:
            permission_dict[permission["permissions__permission_group_id"]]["urls"].append(
                permission["permissions__url"])
            permission_dict[permission["permissions__permission_group_id"]]["codes"].append(
                permission["permissions__code"])
        else:
            permission_dict[permission["permissions__permission_group_id"]] = {
                "urls": [permission["permissions__url"]],
                "codes": [permission["permissions__code"]]
            }
    ‘‘‘
    permission_dict = {
        1:{},
        2:{
            "urls": [],
            "codes": []
        }
    }
    ‘‘‘
    request.session["permission_dict"] = permission_dict

我们可以看到这个方法有两种定义session数据的方式,方式1只是简单的取出数据库中用户拥有权限的url,并添加到一个列表中

而方式2定义了一个如注释中所见的数据形式,将相关数据写入session中后,当用户访问一个url时,我们就可以从session中取出该用户拥有的权限,再验证一下访问的url是否在用户的权限中,如果在,那么就让他通过,不在则返回无权访问

我们发现,不论用户访问哪个url我们都应该做权限的验证,这时就需要使用中间件来解决验证问题了

中间件

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, redirect, HttpResponse
import re

class M1(MiddlewareMixin):

    def process_request(self, request):
        current_path = request.path_info
        # 白名单,当用户访问以下url时直接通过
        valid_url_menu = ["/login/", "/reg/", "/admin/.*"]
        for valid_url in valid_url_menu:
            ret = re.match(valid_url, current_path)
            if ret:
                return None
        # 方式1
        # permissions_list = request.session.get("permission_list")
        # 方式2
        permission_dict = request.session.get("permission_dict")
        if not request.session.get("user_id"):
            return redirect("/login/")

        for item in permission_dict.values():
            regs = item["urls"]
            codes = item["codes"]
            for reg in regs:
                reg = "^%s$" % reg
                ret = re.match(reg, current_path)
                if ret:
                    request.permission_codes = codes
                    return None
        return HttpResponse("无权访问")
        # 方式1
        # flag = False
        # for permission_url in permissions_list:
        #     permission_url = "^%s$" % permission_url
        #     ret = re.match(permission_url, current_path)
        #     if ret:
        #         flag = True
        #         break
        # if not flag:
        #     return HttpResponse("无权访问")

当用户访问时,先取到用户访问的url:request.path_info

有些url我们应该让每个用户都能访问,比如登录、注册页面等

所以我们设置一个白名单,如果用户访问的url在白名单内,则直接通过

如果不在,我们从request.session中取到用户相关的权限,根据我们设置的数据类型,验证用户访问的url是否在权限内

这里要注意,上面我们提到权限是一个url,这里我们还要补充一下,权限是一个包含正则的url,所以在验证是,我们用到了re模块进行正则匹配,同时为了配置的精准,我们在权限前后分别加上了^和$符

当匹配成功后我们将url对应的code列表存到request中,并在中间件中放行

页面上数据的使用

如果用上面的方式1存数据,那么我们能拿到的只是一个url的列表,其中还包含正则表达式,在页面上使用时我们不能使用正则匹配,所以无法进行判断

所以我们使用方式2的数据

视图函数

def orders(request):
    permission_dict = request.session.get("permission_dict")
    permission_codes = request.permission_codes
    per = Permissions(permission_codes)
    return render(request, "orders.html", locals())

这里的Permissions是我们自己定义的一个类,类中定义了判断增删改查是否在permission_codes中的方法,方便我们在前端使用

class Permissions(object):
    def __init__(self, code_list):
        self.code_list = code_list

    def list(self):
        return "list" in self.code_list

    def add(self):
        return "add" in self.code_list

    def delete(self):
        return "delete" in self.code_list

    def edit(self):
        return "edit" in self.code_list

前端页面

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<h3>订单列表</h3>
<div class="col-md-6">
    {% if per.add %}
        <p><a href="/orders/add/"><button class="btn btn-primary pull-right">添加订单</button></a></p>
    {% endif %}

    <table class="table table-stripped">
    <tr>
        <th>订单号</th>
        <th>订单日期</th>
        <th>商品名称</th>
        <th>操作</th>
    </tr>
    <tr>
        <td>12343</td>
        <td>2012-12-12</td>
        <td>li</td>
        {% if per.delete %}
            <td><a href=""><button class="btn btn-danger btn-sm">删除</button></a></td>
        {% endif %}

    </tr>
</table>
</div>

</body>
</html>

前端我们只需要使用per这个对象的方法就能直接判断当前用户有没有对应的权限,从而进行页面渲染

原文地址:https://www.cnblogs.com/QQ279366/p/8525355.html

时间: 2024-10-08 19:25:27

基于角色的权限管理的相关文章

从零开始——基于角色的权限管理01(补充)

此博文较为详细的介绍从零开始--基于角色的权限管理01文中的两个部分的流程(解释代码). 1) index.jsp中提交跳转action action的login,获取jsp页面传过来的用户名密码和验证码,进行验证 首先到userDao中,执行login方法,判断是否存在这组用户名和密码 接着到roleDao中,执行getRoleNameById以获取角色名 最后,进入main.jsp中 2)在main.jsp中,有一个树的显示,再次进入authServlet中执行menuAction   先后

RBAC基于角色的权限管理模型

一.权限管理模型的必要性: a. 安全性:防止误操作,防止数据泄露,保证信息的安全. b. 数据隔离:保持不同的角色具有不同的权限,只能看到自己权限范围内的数据 二.权限管理模型的发展: a. 传统的权限管理:随着用户数量的增大和用户权限区别的增大,传统的权限管理需要针对每个用户依次管理,成本较高. b. RBAC:Role-Based Access Control 用户-角色-权限,权限与角色相关联,用户与角色相关联,通过对用户赋予相应的角色,再去获取相应的权限,从而实现了用户与权限的解耦,具

RBAC 基于角色的权限管理的简单实现

1.什么是权限管理,权限管理就是对后台功能的细分,和对不同工作人员划分不同的工作的管理 RBAC是如何实现的,通过对不同控制器和控制器不同方法的限制,实现的管理. 要实现RBAC需要三张表,一张用户表,一张角色表 ,一张权限表 用户表: id   ******  role_id 角色表 role_id ****** access_ids(记录所有可以访问的权限id) 权限表 access_id    记录所有控制器 或者控制器下的 action 2.如何控制,在控制器的父类 或者控制器的初始化的

基于角色的权限管理系统

我们开发业务系统的时候,基本上都会涉及到权限管理模块,要求不同的人看到不同的菜单,操作不同的按钮,看到不同的数据.很多初学者面对这样的需求不知道如何下手,特别是稍微复杂点的权限,更是找不到方向,为此我们夜鹰教程网特别推出了这套基于角色的权限管理视频教程,通过给用户分配角色,给角色分配权限,来实现权限管理.这样一来,可以实现不同的人管理不同的菜单,操作不同的按钮,看到不同的数据.可以划分权限组,每个组的成员拥有相同的权限.也可以把同一个人分配到不同的权限组,具有多个权限组的权限,实现权限的组合.

webapi框架搭建-安全机制(三)-基于角色的权限控制

webapi框架搭建系列博客 上一篇已经完成了"身份验证",如果只是想简单的实现基于角色的权限管理,我们基本上不用写代码,微软已经提供了authorize特性,直接用就行. Authorize特性的使用方法 配置Authorize 比较简单,直接上代码 using System.Collections.Generic; using System.Net.Http; using System.Security.Claims; using System.Web.Http; using we

【视频分享】Liger UI实战集智建筑工程管理系统配商业代码(打印报表、角色式权限管理)

QQ 2059055336 课程讲师:集思博智 课程分类:.net 适合人群:中级 课时数量:23课时 用到技术:Liger UI框架.AJAX.JSON数据格式的序列化与反序列化.角色的交叉权限管理 本课程代码为商业版代码,用户可直接部署运行. 一.系统介绍: 集智建筑工程管理系统是专为建筑类企业打造的一款管理软件.本着"一工程一台帐"的原则,加强对工程的资金管理,解决工程技术部门.工程管理部门.财务部之间数据的共享,方便领导查询工程进度与回款情况,更好的进行查询统计,提供多种统计图

第二章 基于二进制进行权限管理的理论知识

源代码GitHub:https://github.com/ZhaoRd/Zrd_0001_AuthorityManagement 1.介绍 第一章主要是介绍了这个DEMO的来由和主要使用的技术,这章内容主要是介绍如何通过二进制的位运算进行权限控制的内容. 第一章发布之后,有不少网友.园友反映程序代码运行不起来,很感谢您们的反馈,刚刚进行了代码修复,已经同步到github,感兴趣的朋友可以加我QQ! 2.二进制的位运算以及如何进行权限判断 基于二进制的权限管理,这个内容是我在两年前接触到过的一个知

基于DDDLite的权限管理OpenAuth.net 1.0版正式发布

距离上一篇OpenAuth.net的文章已经有5个多月了,在这段时间里项目得到了很多朋友的认可,开源中国上面的Star数接近300,于是坚定了我做下去的信心.最近稍微清闲点,正式推出1.0版,并在阿里云上部署了一个在线演示(文章结尾处给出在线演示链接).相比刚开始时的版本,现在整个架构已经稳定,系统功能性,代码可读性维护性都有质的飞跃. 本文主要介绍系统结构及未来一段时间的开发计划. 项目简介 本项目采用经典DDD架构(用沃恩.弗农大神的话,其实这是DDD-Lite)思想进行开发的一套符合国情的

使用Lync 2013 基于角色的权限控制:RBAC 给用户分配指定的操作权限

使用场景: 在大型的Lync统一沟通系统的日常运维中,我们需要为不同角色的管理员分配不同的Lync管理权限,在Lync Server 2013上面就使用了基于角色的权限控制:RBAC ,它里面分了多种权限角色,包括 CsAdministrator,CsUserAdministrator,CsVoiceAdministrator,CsServerAdministrator,CsViewOnlyAdministrator,CsHelpDesk等等,不同的角色有不同的Lync管理权限, 例如,当我们只