Rust授权策略框架oso的使用,实现轻量级、高性能的权限管理与访问控制
Rust授权策略框架oso的使用,实现轻量级、高性能的权限管理与访问控制
Oso是一个开源的授权策略框架,可以帮助您在应用程序中构建轻量级、高性能的权限管理和访问控制系统。
Oso简介
Oso是一个功能齐全的框架,用于在您的应用程序中构建授权系统。使用Oso,您可以:
- 建模:使用Oso的内置原语设置常见的权限模式,如基于角色的访问控制(RBAC)和关系。使用Oso的声明性策略语言Polar进行扩展。
- 过滤:超越简单的"是/否"授权问题。对集合实现授权,例如"只显示Juno可以看到的记录"。
- 测试:现在您可以对授权逻辑编写单元测试。使用Oso调试器或REPL跟踪意外行为。
Rust集成
Oso提供了Rust库支持,可以通过Cargo轻松集成到您的项目中:
[dependencies]
oso = "0.27.3"
完整示例
下面是一个完整的Rust示例,展示如何使用Oso实现基本的权限管理:
use oso::{Oso, PolarClass};
use serde::{Deserialize, Serialize};
// 定义用户类型
#[derive(Debug, Clone, PolarClass)]
struct User {
#[polar(attribute)]
name: String,
#[polar(attribute)]
roles: Vec<String>,
}
// 定义资源类型
#[derive(Debug, Clone, PolarClass)]
struct Document {
#[polar(attribute)]
id: String,
#[polar(attribute)]
owner: String,
#[polar(attribute)]
is_public: bool,
}
impl Document {
fn new(id: &str, owner: &str, is_public: bool) -> Self {
Self {
id: id.to_string(),
owner: owner.to_string(),
is_public,
}
}
}
#[tokio::main]
async fn main() -> Result<(), oso::OsoError> {
// 初始化Oso
let mut oso = Oso::new();
// 注册类型
oso.register_class(User::get_polar_class())?;
oso.register_class(Document::get_polar_class())?;
// 加载策略
oso.load_str(r#"
# 用户有"admin"角色可以执行任何操作
allow(user: User, "read", _document: Document) if
"admin" in user.roles;
# 文档所有者可以读取自己的文档
allow(user: User, "read", document: Document) if
user.name == document.owner;
# 任何人都可以读取公开文档
allow(_user: User, "read", document: Document) if
document.is_public;
"#)?;
// 创建测试数据
let admin = User {
name: "admin".to_string(),
roles: vec!["admin".to_string()],
};
let alice = User {
name: "alice".to_string(),
roles: vec![],
};
let bob = User {
name: "bob".to_string(),
roles: vec![],
};
let public_doc = Document::new("public", "alice", true);
let private_doc = Document::new("private", "alice", false);
// 测试授权
println!("Admin can read public doc: {}",
oso.is_allowed(admin.clone(), "read", public_doc.clone())?);
println!("Admin can read private doc: {}",
oso.is_allowed(admin.clone(), "read", private_doc.clone())?);
println!("Alice can read her private doc: {}",
oso.is_allowed(alice.clone(), "read", private_doc.clone())?);
println!("Bob can read public doc: {}",
oso.is_allowed(bob.clone(), "read", public_doc.clone())?);
println!("Bob can read private doc: {}",
oso.is_allowed(bob, "read", private_doc)?);
Ok(())
}
示例解释
-
定义模型:我们定义了
User
和Document
结构体,并使用PolarClass
派生宏使它们可用于Oso策略。 -
策略规则:我们定义了三条授权规则:
- 管理员可以读取任何文档
- 文档所有者可以读取自己的文档
- 任何人都可以读取公开文档
-
测试授权:我们创建了几个测试用户和文档,然后使用
oso.is_allowed()
方法测试不同的授权场景。
性能特点
Oso在Rust中实现,具有以下性能优势:
- 轻量级:核心授权检查非常高效
- 低延迟:策略评估速度快
- 内存高效:策略引擎优化良好
社区支持
如果您有任何关于Oso或授权的问题,可以加入社区Slack获取支持。
注意事项
请注意,Oso开源库已进入维护阶段,团队正在规划下一个开源版本。当前版本仍将继续获得支持和关键错误修复。
完整示例demo
基于上述内容,下面是一个更完整的Oso使用示例,展示了如何实现基于角色的访问控制(RBAC):
use oso::{Oso, PolarClass};
use serde::{Deserialize, Serialize};
// 定义用户角色枚举
#[derive(Debug, Clone, PartialEq)]
enum Role {
Admin,
Editor,
Viewer,
}
// 定义用户类型
#[derive(Debug, Clone, PolarClass)]
struct User {
#[polar(attribute)]
name: String,
#[polar(attribute)]
roles: Vec<Role>,
}
// 定义文章资源类型
#[derive(Debug, Clone, PolarClass)]
struct Article {
#[polar(attribute)]
id: String,
#[polar(attribute)]
title: String,
#[polar(attribute)]
author: String,
#[polar(attribute)]
status: ArticleStatus,
}
// 定义文章状态枚举
#[derive(Debug, Clone, PartialEq, PolarClass)]
enum ArticleStatus {
Draft,
Published,
Archived,
}
impl Article {
fn new(id: &str, title: &str, author: &str, status: ArticleStatus) -> Self {
Self {
id: id.to_string(),
title: title.to_string(),
author: author.to_string(),
status,
}
}
}
#[tokio::main]
async fn main() -> Result<(), oso::OsoError> {
// 初始化Oso
let mut oso = Oso::new();
// 注册自定义类型
oso.register_class(User::get_polar_class())?;
oso.register_class(Article::get_polar_class())?;
oso.register_enum(ArticleStatus::get_polar_class())?;
// 加载更复杂的策略规则
oso.load_str(r#"
# 管理员可以做任何事
allow(user: User, _action: String, _resource: Article) if
Role::Admin in user.roles;
# 编辑可以发布文章
allow(user: User, "publish", article: Article) if
Role::Editor in user.roles and
article.status == ArticleStatus::Draft;
# 作者可以编辑自己的草稿文章
allow(user: User, "edit", article: Article) if
user.name == article.author and
article.status == ArticleStatus::Draft;
# 任何人都可以查看已发布的文章
allow(_user: User, "view", article: Article) if
article.status == ArticleStatus::Published;
"#)?;
// 创建测试用户
let admin = User {
name: "admin".to_string(),
roles: vec![Role::Admin],
};
let editor = User {
name: "editor1".to_string(),
roles: vec![Role::Editor],
};
let author = User {
name: "author1".to_string(),
roles: vec![Role::Viewer],
};
// 创建测试文章
let draft_article = Article::new(
"draft1",
"Rust Oso Guide",
"author1",
ArticleStatus::Draft
);
let published_article = Article::new(
"pub1",
"Published Article",
"editor1",
ArticleStatus::Published
);
// 测试授权
println!("Admin can edit any article: {}",
oso.is_allowed(admin.clone(), "edit", draft_article.clone())?);
println!("Editor can publish draft: {}",
oso.is_allowed(editor.clone(), "publish", draft_article.clone())?);
println!("Author can edit own draft: {}",
oso.is_allowed(author.clone(), "edit", draft_article.clone())?);
println!("Viewer can view published article: {}",
oso.is_allowed(author.clone(), "view", published_article.clone())?);
Ok(())
}
这个扩展示例展示了:
- 使用枚举类型定义角色和文章状态
- 实现更复杂的RBAC策略
- 基于资源状态的权限控制
- 多种操作类型(查看、编辑、发布)的权限管理
1 回复
Rust授权策略框架oso的使用:实现轻量级、高性能的权限管理与访问控制
完整示例代码
下面是一个完整的Rust应用示例,展示了如何使用oso进行权限管理:
use oso::{Oso, PolarClass};
use serde::{Serialize, Deserialize};
use chrono::Utc;
// 定义用户结构体
#[derive(Clone, Serialize, Deserialize, PolarClass)]
struct User {
#[polar(attribute)]
id: i32,
#[polar(attribute)]
role: String,
#[polar(attribute)]
allowed_access_hours: (i32, i32), // (开始小时, 结束小时)
}
// 定义文档结构体
#[derive(Clone, Serialize, Deserialize, PolarClass)]
struct Document {
#[polar(attribute)]
id: i32,
#[polar(attribute)]
owner_id: i32,
#[polar(attribute)]
is_public: bool,
#[polar(attribute)]
created_at: i64,
}
// 自定义时间检查函数
fn time_in_range(range: (i32, i32), timestamp: i64) -> bool {
let hour = Utc.timestamp(timestamp, 0).hour() as i32;
hour >= range.0 && hour <= range.1
}
fn main() -> anyhow::Result<()> {
// 初始化oso引擎
let mut oso = Oso::new();
// 注册自定义类型
oso.register_class(User::get_polar_class())?;
oso.register_class(Document::get_polar_class())?;
// 注册自定义函数
oso.register_fn(time_in_range)?;
oso.register_constant("current_time", Utc::now().timestamp())?;
// 加载策略规则
oso.load_str(r#"
# 管理员可以做任何事
allow(_user: User, _action: String, _resource: Document) if
user.role = "admin";
# 文档所有者可以编辑自己的文档
allow(user: User, "edit", document: Document) if
document.owner_id = user.id;
# 任何人都可以读取公共文档
allow(_user: User, "read", document: Document) if
document.is_public = true;
# 在允许访问时间内可以访问
allow(user: User, "access", _: Document) if
time_in_range(user.allowed_access_hours, current_time);
"#)?;
// 创建测试用户和文档
let admin = User {
id: 1,
role: "admin".to_string(),
allowed_access_hours: (0, 23),
};
let regular_user = User {
id: 2,
role: "user".to_string(),
allowed_access_hours: (9, 17),
};
let public_doc = Document {
id: 1,
owner_id: 1,
is_public: true,
created_at: Utc::now().timestamp(),
};
let private_doc = Document {
id: 2,
owner_id: 1,
is_public: false,
created_at: Utc::now().timestamp(),
};
// 测试权限检查
println!("Admin can edit public doc: {}",
oso.is_allowed(admin.clone(), "edit", public_doc.clone())?);
println!("Regular user can read public doc: {}",
oso.is_allowed(regular_user.clone(), "read", public_doc.clone())?);
println!("Regular user can edit private doc: {}",
oso.is_allowed(regular_user.clone(), "edit", private_doc.clone())?);
println!("Regular user can access during allowed hours: {}",
oso.is_allowed(regular_user.clone(), "access", private_doc.clone())?);
// 批量授权检查示例
let users = vec![admin.clone(), regular_user.clone()];
let documents = vec![public_doc.clone(), private_doc.clone()];
println!("\n批量授权检查结果:");
for user in users {
for document in &documents {
println!(
"用户 {} 可以读取文档 {}: {}",
user.id,
document.id,
oso.is_allowed(user.clone(), "read", document.clone())?
);
}
}
// 数据过滤示例
println!("\n可读文档过滤:");
let query = oso.authorized_query(regular_user, "read", Document::get_polar_class())?;
let readable_docs: Vec<Document> = query.collect()?;
for doc in readable_docs {
println!("用户可读取文档: {}", doc.id);
}
Ok(())
}
代码说明
-
数据结构定义:
User
结构体表示系统用户,包含ID、角色和允许访问时间段Document
结构体表示文档资源,包含ID、所有者ID、是否公开和创建时间
-
自定义函数:
time_in_range
函数检查当前时间是否在允许访问的时间段内
-
oso初始化:
- 创建oso实例并注册自定义类型
- 注册自定义函数和常量
-
策略规则:
- 管理员拥有所有权限
- 文档所有者可以编辑自己的文档
- 公开文档可被所有人读取
- 只能在允许的时间段内访问
-
测试用例:
- 创建管理员和普通用户
- 创建公开和私有文档
- 进行各种权限检查
- 演示批量授权检查
- 展示数据过滤功能
运行结果示例
程序运行后会输出类似以下结果:
Admin can edit public doc: true
Regular user can read public doc: true
Regular user can edit private doc: false
Regular user can access during allowed hours: true
批量授权检查结果:
用户 1 可以读取文档 1: true
用户 1 可以读取文档 2: true
用户 2 可以读取文档 1: true
用户 2 可以读取文档 2: false
可读文档过滤:
用户可读取文档: 1
这个完整示例展示了oso在Rust中的主要功能,包括策略定义、权限检查、批量授权和数据过滤等。