【RBAC鉴权】node-casbin基础教程

news2024/11/24 0:59:37

一、RBAC概述

RBAC鉴权,完整的英文描述是:Role-Based Access Control,中文意思是:基于角色(Role)的访问控制。这是一种广泛应用于计算机系统和网络安全领域的访问控制模型。

简单来说,就是通过将权限分配给➡角色,再将角色分配给➡用户,来实现对系统资源的访问控制。一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系。具体而言,RBAC模型定义了以下几个核心概心概念:

  • 角色(Role):角色是指在系统中具有一组相关权限的抽象概念,代表了用户在特定上下文中的身份或职能,例如管理员、普通用户等。

  • 权限(Permission):权限是指对系统资源进行操作的许可,如读取、写入、修改等。权限可以被分配给角色。

  • 用户(User):用户是指系统的实际使用者,每个用户可以被分配一个或多个角色。

  • 分配(Assignment):分配是指将角色与用户关联起来,以赋予用户相应的权限。

具体的鉴权逻辑如下图,也可以直接参考RBAC角色权限设计:

img_d55912967bd28f3392f56bd216392ec3.png

简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系。

二、node-casbin使用模型

这里使用nestjs脚手架做实战演练。

1、安装

# NPM
npm install casbin --save

# Yarn
yarn add casbin

# pnpm
pnpm add casbin

2、开始使用

node-casbin使用模型文件和策略文件新建一个执行器,有关详细信息,请参阅模型部分,也可以直接查看源码中examples目录下的模型文件:

  1. auth.controller.ts 控制器入口:

    提供api访问入口:/auth/getPermission

import { Controller, Get, Post, Body, Req } from '@nestjs/common';
import { AuthService } from '@/auth/auth.service';
import { Public } from '@/auth/decorators/public.decorator';
import { ApiTags } from '@nestjs/swagger';

@Controller('auth')
@ApiTags("Auth")
export class AuthController {
  constructor(private readonly authService: AuthService) { }
  @Get('/getPermission')
  getPermission(): any {
    return this.authService.getPermission();
  }
}
  1. auth.services.ts 服务方法:

    提供getPermission()方法。

import { UserService } from '@/module/user/user.service';
import {
  Injectable
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { PasswordService } from './password.service';
import Permission from './permission';

@Injectable()
export class AuthService {
  constructor() { }

  async getPermission(): Promise<any> {
    await Permission.init();
    const r:string = Permission.getPermission();
    return r;
  }
}
  1. permission.ts 权限控制类:
import { Enforcer, newEnforcer } from "casbin";

export default class Permission {
  private static enforcerIns: Enforcer

  /**
   * 初始化权限实例
   */
  public static async init() {
    try {
      const path_prefix = "src/auth/permission";   //默认指向项目根目录,不需要:/
      this.enforcerIns = await newEnforcer(`${path_prefix}/basic_model.conf`, `${path_prefix}/basic_policy.csv`);
    } catch (error) {
      throw new Error(error?.message);
    }
  }

  /**
   * 获取权限
   * @param user 用户
   * @param resource 要访问的资源
   * @param action 权限:read、write,此处权限可以进行自定义扩展
   */
  public static async getPermission(user: string = "alice", resource: string = "data1", action: string = "read") {
    // 异步:
    const res:boolean = await this.enforcerIns.enforce(user, resource, action);
    // 同步:
    // const res = enforcer.enforceSync(sub, obj, act);
 
    if (res) {
      return "ok";
      // 允许 alice 读取 data1
    } else {
      return "error";
      // 访问拒绝
    }
  }
}

控制类中提供casbin权限控制器的初始化,并提供权限查询方法getPermission();

  1. basic_model.conf 模型文件:
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

上述配置说明如下:

  • request_definition:部分用于request的定义,它明确了 e.Enforce(...) 函数中参数的含义。sub, obj, act 表示经典三元组: 访问实体 (Subject),访问资源 (Object) 和访问方法 (Action)

  • policy_definition:对policy的定义,可以理解为对上述request_definition中传入的参数的载体。例如:p = sub, obj, act就和r = sub, obj, act要一致。

  • policy_effect:策略效果的定义。 它确定如果多项政策规则与请求相符,是否应批准访问请求。例如:e = some(where (p.eft == allow))就表示只要有一个匹配的策略规则,那么就允许e = some(where (p.eft == allow)) && !some(where (p.eft == deny))就表示只要有一条匹配的策略规则,并且没有匹配拒绝的策略规则,那么就允许

  • matchers:是策略匹配程序的定义。匹配程序是表达式。它定义了如何根据请求评估策略规则。例如:m = r.sub == p.sub && r.obj == p.obj && r.act == p.act,表示请求中的主题(用户)、对象(带访问资源)和行动(操作权限)应该与政策规则中的匹配。

    关于模型语法的更多说明,请查看casbin模型语法

  1. basic_policy.csv 策略文件:
p, alice, data1, read
p, bob, data2, write

上述配置意味着:

  • alice可以读取data1
  • bob可以编写data2

3、执行

这时候我们发起POST请求/auth/getPermission后,在permission.ts控制器中查看结果,可以看到权限是true

image-20240502172702832

不同入参对应的权限判断结果如下:

Permission.getPermission("alice", "data1", "read");		//有权限:true
Permission.getPermission("alice", "data1", "write");	//无权限:false
Permission.getPermission("bob", "data2", "write");		//有权限:true
Permission.getPermission("bob", "data2", "read");		//无权限:false

4、动态添加策略

用户或者角色有什么对应角色,我们一般是存储在数据库中,那么我们就需要动态读取数据库的权限策略。node-casbin中是提供了addPolicy(user, resource, action)方法。

permission.ts 文件

import { Enforcer, newEnforcer } from "casbin";

export default class Permission {
  private static enforcerIns: Enforcer

  /**
   * 初始化权限实例
   */
  public static async init() {
    try {
      const path_prefix = "src/auth/permission";   //默认指向项目根目录,不需要:/
      this.enforcerIns = await newEnforcer(`${path_prefix}/basic_model.conf`, `${path_prefix}/basic_policy.csv`);

	  // 读取mysql数据,并在此处批量添加策略
      // await this.enforcerIns.addPolicy("bob", "data2", "read");		//单个添加
      await this.enforcerIns.addPolicies([["bob", "data2", "read"]]);	//批量添加
    } catch (error) {
      throw new Error(error?.message);
    }
  }

  /**
   * 获取权限
   * @param user 用户
   * @param resource 要访问的资源
   * @param action 权限:read
   */
  public static async getPermission(user: string = "alice", resource: string = "data1", action: string = "read") {
    const res = await this.enforcerIns.enforce(user, resource, action);
    if (res) {
      return "ok";
    } else {
      return "error";
    }
  }
}

5、分组模型和略测配置

# 模型
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
#策略
p, alice, data1, read
p, bob, data2, write
p, data2_admin, data2, read
p, data2_admin, data2, write
g, alice, data2_admin

上述策略表示:

  • alicedata1read权限
  • bobdata2write权限
  • data2_admin角色对data2read权限
  • data2_admin角色对data2write权限
  • alice属于data2_admin角色

6、其他Api

  • enforcerIns.LoadModel():从*.conf文件重新加载模型
  • enforcerIns.LoadPolicy():从*.csv文件中重新加载策略
  • enforcerIns.SavePolicy():把当前策略重新写入*.csv文件
  • enforcerIns.removePolicies([["bob", "data2", "read"]]):批量删除策略
  • enforcerIns.removePolicy("alice", "data1", "read"):删除策略
  • enforcerIns.getRolesForUser("alice"):读取用户归属的角色

更多Api请查看:Adapters

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1640084.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

a-table 控制列的展示和隐藏

一、业务场景&#xff1a; 最近在使用 Antd-vue 组件库的时候&#xff0c;a-table需要根据不同角色的权限显示和隐藏 columns的列 为了避免大家走弯路&#xff0c;为大家整理了一下&#xff0c;粘走可以直接用的那种 二、具体实现步骤&#xff1a; 1.在需要显示与隐藏的列增加一…

Android Studio实现简单的自定义钟表

项目目录 一、项目概述二、开发环境三、详细设计3.1、尺寸设置3.2、绘制表盘和指针3.3、动态效果 四、运行演示五、总结展望六、源码获取 一、项目概述 在安卓开发中&#xff0c;当系统自带的View已经无法满足项目需求时&#xff0c;就要自定义View。在Android中是没有与钟表有…

深度学习之基于Matlab BP神经网络烟叶成熟度分类

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 烟叶的成熟度是评估烟叶品质的重要指标之一&#xff0c;它直接影响着烟叶的口感、香气和理化特性。传…

jupyter notebook切换conda虚拟环境

首先&#xff0c;切换到某个虚拟环境&#xff0c;本人切换到了d2l环境&#xff1a; (d2l) C:\Users\10129>pip install ipykernel然后&#xff0c;如代码所示安装ipykernel包 最后&#xff0c;按下述代码执行&#xff1a; (d2l) C:\Users\10129>python -m ipykernel i…

软件工程全过程性文档(软件全套文档整理)

软件项目相关全套精华资料包获取方式①&#xff1a;进主页。 获取方式②&#xff1a;本文末个人名片直接获取。 在软件开发的全过程中&#xff0c;文档是记录项目进展、决策、设计和测试结果的重要工具。以下是一个简要的软件全过程性文档梳理清单&#xff1a; 需求分析阶段…

Ex1-C6油气化工防爆轮式巡检机器人

Ex1系列防爆轮式巡检机器人整机采用防爆设计&#xff0c;防爆等级为Exd II CT4 Gb。机器人通过无轨3D形态导航技术&#xff0c;结合360度防爆云台和无线防爆充电桩&#xff0c;实现整套防爆标准&#xff0c;可广泛应用于石油、燃气、化工、冶金等II类爆炸环境中&#xff0c;代替…

【Qt QML】QLibrary加载共享库中的类

QLibrary是一个用于加载动态链接库&#xff08;或称为共享库&#xff09;的类。它提供了一种独立于平台的方式来访问库中的功能。 在QLibrary中&#xff0c;可以通过构造函数或setFileName()方法设置要加载的库文件名。当加载库文件时&#xff0c;QLibrary会搜索所有平台特定的…

VmWare 虚拟机没有网络解决办法

由于最近需要&#xff0c;装了个VM虚拟机&#xff0c;但是突然发现本机有网络&#xff0c;虚拟机却没有网络&#xff0c;更换了虚拟机的网络设置&#xff0c;都尝试过了 都不管用&#xff0c; 最后尝试了这种方法完美解决 还原网络默认设置 首先还原虚拟网络编辑器设置 启动V…

Re69:读论文 LaMDA: Language Models for Dialog Applications

诸神缄默不语-个人CSDN博文目录 诸神缄默不语的论文阅读笔记和分类 论文名称&#xff1a;LaMDA: Language Models for Dialog Applications ArXiv网址&#xff1a;https://arxiv.org/abs/2201.08239 本文介绍谷歌提出的对话大模型LaMDA&#xff0c;主要关注对各项指标&#x…

使用 MediaMTX 和 FFmpeg 推拉 RTSP 流媒体

实时流传输协议 RTSP&#xff08;Real-Time Streaming Protocol&#xff09;是 TCP/IP 协议体系中的一个应用层协议&#xff0c;由哥伦比亚大学、网景和 RealNetworks 公司提交的 IETF RFC 标准。该协议定义了一对多应用程序如何有效地通过 IP 网络传送多媒体数据。RTSP 在体系…

idea常用知识点随记

idea常用知识点随记 1. 打开idea隐藏的commit窗口2. idea中拉取Git分支代码3. idea提示代码报错&#xff0c;项目编译没有报错4. idea中实体类自动生成序列号5. idea隐藏当前分支未commit代码6. idea拉取新建分支的方法 1. 打开idea隐藏的commit窗口 idea左上角File→Settings…

Linux的软件包管理器-yum

文章目录 软件包的概念yum源的配置的原因yum的使用查看软件包安装软件卸载软件 软件包的概念 软件包(SoftWare Package)是指具有特定的功能&#xff0c;用来完成特定任务的一个程序或一组程序。可分为应用软件包和系统软件包两大类 在Linux系统中&#xff0c;下载安装软件的方式…

设计模式: 模板模式

目录 一&#xff0c;模板模式 二&#xff0c;特点 三&#xff0c;组成部分 四&#xff0c;实现步骤 五&#xff0c;案例 一&#xff0c;模板模式 模板模式&#xff08;Template Pattern&#xff09;是一种行为型设计模式&#xff0c;它在超类中定义了一个算法的骨架&#…

React Native支持Tailwind CSS 语法

React Native支持Tailwind CSS 语法 一、前沿背景 回想下我们平时按照官方的规范进行书写样式是什么样&#xff1f; 是像下面这样&#xff1a; const MyComponent () > {return (<View><Text style{{ fontSize: 20 }}>开发者演示专用</Text></View…

每日一题(力扣213):打家劫舍2--dp+分治

与打家劫舍1不同的是它最后一个和第一个会相邻&#xff0c;事实上&#xff0c;从结果思考&#xff0c;最后只会有三种&#xff1a;1 第一家不被抢 最后一家被抢 2 第一家被抢 最后一家不被抢 3 第一和最后一家都不被抢 。那么&#xff0c;根据打家劫舍1中的算法 我们能算出在i…

【linux】进程间通信(匿名管道)

对于本篇文章我们采取三段论&#xff1a;是什么 为什么 怎么办。 目录 进程间为什么要通信&#xff1f;进程间如何通信&#xff1f;进程间怎么通信&#xff1f;匿名管道&#xff1a;匿名管道原理&#xff1a;代码示例&#xff1a;匿名管道的情况与特征&#xff1a; 进程间为什…

Debian 12 tomcat 9 catalina 日志信息 中文显示乱码

目录 问题现象 解决办法&#xff1a; 1、设定Debian locale 2、设定catalina.sh utf8字符集 问题现象 Debian 12 linux操作系统中&#xff0c;tomcat 9 catalina 启动日志输出 中文乱码 解决办法&#xff1a; 1、设定Debian locale 先确保系统本身就支持中文的 Debian …

【数据结构】算法的效率(时间复杂度和空间复杂度)

目录 一.算法的效率 二.时间复杂度 1.概念 2.大O的渐进表示法 3.常见时间复杂度计算举例 三.空间复杂度 四.常见复杂度对比 五. 复杂度的oj练习 1.消失的数字 2.轮转数字&#xff1a; 一.算法的效率 算法在编写成可执行程序后&#xff0c;运行时需要耗费时间资源和空…

uniapp 异步加载级联选择器(Cascader,data-picke)

目录 Props 事件方法 inputChange事件回调参数说明&#xff1a; completeChange事件回调参数说明&#xff1a; temList 属性Object参数说明 defaultItemList 属性Object参数说明 在template中使用 由于uniapp uni-ui的data-picke 不支持异步作者自己写了一个 插件市场下…

Deep Learning Part Seven基于RNN生成文本--24.5.2

不存在什么完美的文章&#xff0c;就好像没有完美的绝望。 ——村上春树《且听风吟》 本章所学的内容 0.引子 本章主要利用LSTM实现几个有趣的应用&#xff1a; 先剧透一下&#xff1a;是AI聊天软件&#xff08;现在做的ChatGPT&#xff08;聊天神器&#xff0c;水论文高手…