ABAC 模型在列表查询中的应用
查询接口使用 ABAC 策略模型 ABAC 策略处理逻辑扩展为一个 通用 Node.js 类,它可以根据策略自动生成 MongoDB 查询过滤条件,用于在「列表查询接口」中动态控制数据可见性。 🎯 设计目标 这个类要做到以下几点: 支持加载多条策略; 根据用户信息(roles, attributes 等)和操作类型(action)生成 MongoDB 查询过滤条件; 支持组合策略(多策略叠加); 支持多种条件表达式(==, !=, in, not in, and, or, >,<,>=,<=等); 输出标准 MongoDB 查询对象,可直接传入 Model.find(filter)。 🧩 策略示例 const policies = [ { name: 'operator-view-online', effect: 'allow', subjectExpr: 'operator', resourceExpr: 'device', action: 'view', condition: { and: [ { in: ['operator', { var: 'user.roles' }] }, { '==': [{ var: 'resource.status' }, 'online'] } ] }, priority: 5 }, { name: 'manager-view-all', effect: 'allow', subjectExpr: 'manager', resourceExpr: 'device', action: 'view', condition: { in: ['manager', { var: 'user.roles' }] }, priority: 10 } ]; 🧱 通用 ABAC 查询构造类 class ABACQueryBuilder { constructor(policies = []) { this.policies = policies; } /** * 生成 MongoDB 查询过滤条件 * @param {Object} user - 用户信息,如 { id, roles, projectId, department } * @param {String} action - 动作,如 'view', 'edit' * @param {String} resource - 资源类型,如 'device', 'product' * @returns {Object} MongoDB 查询条件 */ buildQuery(user, action, resource) { const matchedPolicies = this.policies .filter(p => p.action === action && p.resourceExpr === resource) .sort((a, b) => b.priority - a.priority); if (matchedPolicies.length === 0) { return { _id: { $exists: false } }; // 无策略则拒绝访问 } const allowFilters = []; const denyFilters = []; for (const policy of matchedPolicies) { const condition = this._evaluateCondition(policy.condition, user); if (!condition) continue; const filter = this._conditionToMongo(policy.condition, user); if (policy.effect === 'allow') { allowFilters.push(filter); } else { denyFilters.push(filter); } } // 最终 MongoDB 查询组合规则 let query = {}; if (allowFilters.length > 0) { query = { $or: allowFilters }; } if (denyFilters.length > 0) { query = { $and: [query, { $nor: denyFilters }] }; } return query; } /** * 将条件表达式转换为 MongoDB 查询过滤条件 */ _conditionToMongo(condition, user) { if (!condition) return {}; if (condition.and) { return { $and: condition.and.map(c => this._conditionToMongo(c, user)) }; } if (condition.or) { return { $or: condition.or.map(c => this._conditionToMongo(c, user)) }; } const key = Object.keys(condition)[0]; const [left, right] = condition[key]; const leftVal = this._resolveVar(left, user); const rightVal = this._resolveVar(right, user); switch (key) { case '==': if (this._isResourceVar(left)) { return { [leftVal]: rightVal }; } else if (this._isResourceVar(right)) { return { [rightVal]: leftVal }; } return {}; case '!=': if (this._isResourceVar(left)) { return { [leftVal]: { $ne: rightVal } }; } return {}; case 'in': if (this._isResourceVar(left)) { return { [leftVal]: { $in: rightVal } }; } else if (this._isResourceVar(right)) { return { [rightVal]: { $in: leftVal } }; } return {}; case 'not in': if (this._isResourceVar(left)) { return { [leftVal]: { $nin: rightVal } }; } return {}; case '>': if (this._isResourceVar(left)) { return { [leftVal]: { $gt: rightVal } }; } break; case '>=': if (this._isResourceVar(left)) { return { [leftVal]: { $gte: rightVal } }; } break; case '<': if (this._isResourceVar(left)) { return { [leftVal]: { $lt: rightVal } }; } break; case '<=': if (this._isResourceVar(left)) { return { [leftVal]: { $lte: rightVal } }; } break; default: return {}; } return {}; } /** * 判断 { var: 'xxx' } 是否为资源变量 */ _isResourceVar(value) { return typeof value === 'object' && value.var && value.var.startsWith('resource.'); } /** * 从 { var: 'user.xxx' } 中解析变量 */ _resolveVar(expr, user) { if (typeof expr !== 'object' || !expr.var) return expr; const path = expr.var.split('.'); if (path[0] === 'user') { return path.slice(1).reduce((obj, key) => obj?.[key], user); } else if (path[0] === 'resource') { return path.slice(1).join('.'); // 资源字段返回为路径字符串 } return expr; } /** * 简单评估条件(判断用户是否符合该策略) */ _evaluateCondition(condition, user) { if (!condition) return true; if (condition.and) return condition.and.every(c => this._evaluateCondition(c, user)); if (condition.or) return condition.or.some(c => this._evaluateCondition(c, user)); const key = Object.keys(condition)[0]; const [left, right] = condition[key]; const leftVal = this._resolveVar(left, user); const rightVal = this._resolveVar(right, user); switch (key) { case '==': return leftVal === rightVal; case '!=': return leftVal !== rightVal; case 'in': return Array.isArray(rightVal) ? rightVal.includes(leftVal) : false; case 'not in': return Array.isArray(rightVal) ? !rightVal.includes(leftVal) : false; case '>': return leftVal > rightVal; case '>=': return leftVal >= rightVal; case '<': return leftVal < rightVal; case '<=': return leftVal <= rightVal; default: return false; } } } ✅ 使用示例 const user = { id: 'u1', roles: ['operator'], projectId: 'p1' }; const qb = new ABACQueryBuilder(policies); // 生成设备列表过滤条件 const mongoFilter = qb.buildQuery(user, 'view', 'device'); console.log(JSON.stringify(mongoFilter, null, 2)); /* 输出: { "$or": [ { "status": "online" } ] } */ // 可直接用于 Mongoose 查询 // DeviceModel.find(mongoFilter) 🧠 特点总结 策略驱动查询:无须在代码中硬编码角色逻辑; 灵活扩展:新增策略只需在数据库或配置中定义; 兼容性好:输出标准 MongoDB 查询条件; 安全可控:未匹配策略默认拒绝访问。 非常好 👍,我们现在在上面的 ABACQueryBuilder 基础上,扩展出一个适用于 Node.js + Express + MongoDB (Mongoose) 的 通用权限中间件系统。 ...
混合型权限系统(RBAC + ABAC Hybrid Access Control)
在 IoT SaaS 系统(物联网多租户云平台)中,权限体系的设计至关重要,因为它不仅要满足传统的 用户-角色-权限 管理,还要处理 设备、产品、项目、组织、租户、数据流、操作权限 等多维场景。 单一的 RBAC 模型在 IoT 场景中往往不够灵活,因此需要引入 RBAC + ABAC 的混合设计。 下面将分 7 个部分为你完整讲解 IoT SaaS 系统中的 RBAC + ABAC 混合权限模型设计,并提供可直接落地的通用范例。 🧩 一、IoT SaaS 系统的权限需求特征 IoT 平台的典型多维结构如下: 租户(Tenant) └── 项目(Project) ├── 产品(Product) │ ├── 设备(Device) │ ├── 功能点(Feature) │ └── 数据流(Telemetry) └── 成员(User) 主要权限控制目标: 维度 示例需求 用户 → 资源 某个用户是否能查看设备详情 用户 → 动作 某个用户是否能远程控制设备 状态条件 设备在线时才允许下发指令 数据隔离 不同租户、项目、产品的数据隔离 动态策略 不同产品状态、设备类型、标签影响权限 运维与监管 部分角色仅能查看但不能操作设备 这些场景无法单靠 RBAC 静态角色覆盖,因此引入 ABAC 动态属性判定。 ...
AI学英语计划
来源:deepseek 第一阶段:基础搭建(1-3个月) 目标:掌握技术场景高频词汇,建立基本听力反应能力 1. 每日学习模块(6:00-7:30) 时间 内容 具体方法 6:00 唤醒耳朵(15min) 听慢速技术播客(如《Software Engineering Daily》慢速版),仅专注识别关键词 6:15 核心词汇突破(30min) - 用Anki记忆卡背技术高频词(附推荐词表)- 结合代码注释练习造句 6:45 结构化输入(30min) - 精读GitHub英文README文件- 用彩笔标注:功能描述/报错处理/API用法 7:15 影子跟读(15min) 跟读技术教程短视频(如Fireship.io),模仿语调,不求全懂 重点工具: 词汇表:Tech English 3000词表(优先掌握前500词) 听力材料:YouTube频道《Learn English with Code》慢速版 阅读材料:精选10个Star>1k的GitHub项目文档 第二阶段:实战强化(4-6个月) 目标:听懂技术视频核心逻辑,流畅阅读官方文档 1. 每日学习模块(6:00-7:30) 时间 内容 具体方法 6:00 沉浸式听力(30min) 看YouTube技术视频(如AWS re:Invent演讲):- 第一遍关字幕抓主干- 第二遍开英文字幕补细节 6:30 文档解剖术(30min) 精读Stack Overflow高票答案+官方文档(如React Docs):- 用思维导图梳理逻辑链- 摘录万能句式(如"How to troubleshoot X") 7:00 场景输出(30min) - 用英语写代码注释- 在Reddit的r/learnprogramming版块回答简单问题 关键技巧: 听力突破:使用Chrome插件Language Reactor,自动生成双语字幕并标记高频词 阅读加速:安装Readwise高亮整理工具,建立个人技术英语语料库 查词策略:用剑桥技术词典而非普通词典,理解术语精准定义 第三阶段:自主应用(7-9个月) 目标:无字幕看懂技术会议视频,30分钟内速读英文RFC文档 ...
Go 标准库学习
快速学习Go标准库的方法 Go标准库是Go语言强大功能的核心部分,学习标准库可以显著提高开发效率和代码质量。以下是系统学习Go标准库的方法: 1. 结构化学习路径 基础核心库(先掌握这些) fmt:格式化输入输出 os:操作系统功能接口 io/ioutil:I/O操作 strings:字符串处理 strconv:字符串转换 time:时间日期处理 errors:错误处理 sort:排序功能 中级重要库 bufio:缓冲I/O encoding/json:JSON处理 net/http:HTTP客户端和服务端 sync:并发同步原语 flag:命令行参数解析 path/filepath:文件路径处理 regexp:正则表达式 高级专业库 context:上下文管理 database/sql:数据库接口 crypto:加密相关 reflect:反射 runtime:运行时接口 testing:测试功能 2. 高效学习方法 实践驱动学习法 小项目实践:为每个库创建小型示例项目 // strings库示例 package main import ( "fmt" "strings" ) func main() { fmt.Println(strings.Contains("hello", "he")) // true fmt.Println(strings.ToUpper("hello")) // HELLO fmt.Println(strings.Split("a,b,c", ",")) // [a b c] } 修改官方示例:在pkg.go.dev上找到官方示例并修改实验 每日一库计划 每天专注学习1-2个标准库 记录学习笔记和代码片段 周末回顾并整合所学内容 3. 利用优质资源 官方资源 Go标准库文档 Go by Example Go官方博客 书籍推荐 《Go语言标准库》 《Go程序设计语言》(The Go Programming Language) 4. 实用技巧 IDE集成:使用VS Code或GoLand的代码补全和文档查看功能 源码阅读:直接阅读标准库源码(位于Go安装目录的src文件夹) 测试驱动:为学习的库编写测试用例 func TestStrings(t *testing.T) { if !strings.Contains("hello", "he") { t.Error("Contains failed") } } 比较学习:对比相似功能的不同实现(如bytes vs strings) 5. 学习路线图示例 阶段 时间 内容 产出物 1 第1周 基础I/O、字符串、错误处理 10个实用代码片段 2 第2周 文件操作、时间、命令行参数 小型文件处理工具 3 第3周 并发、HTTP、JSON 简易HTTP服务 4 第4周 数据库、测试、高级特性 带测试的数据库应用 6. 避免的常见误区 贪多求全:不要试图一次性记住所有API 只看不练:必须动手编写代码 忽视文档:标准库文档包含丰富示例和用法说明 过早优化:先掌握基本用法,再研究高级技巧 通过系统化的学习和持续的实践,你可以在4-6周内掌握Go标准库的核心内容,并在实际开发中熟练运用。
国家网站列表
国家官方网站合集