Rust权限管理库oso-derive的使用:基于宏的声明式授权策略与RBAC访问控制
Rust权限管理库oso-derive的使用:基于宏的声明式授权策略与RBAC访问控制
Oso是一个内置电池的框架,用于在应用程序中构建授权系统。通过Oso,您可以:
- 建模:使用Oso内置的原语设置常见的权限模式,如基于角色的访问控制(RBAC)和关系。使用Oso的声明性策略语言Polar进行扩展。
- 过滤:超越简单的"是/否"授权问题。实现对集合的授权 - 例如,“只显示Juno可以看到的记录”。
- 测试:现在您可以对授权逻辑编写单元测试。使用Oso调试器或REPL跟踪意外行为。
安装
在项目目录中运行以下Cargo命令:
cargo add oso-derive
或者在Cargo.toml中添加:
oso-derive = "0.27.3"
示例代码
下面是一个完整的基于RBAC的授权示例:
use oso_derive::*;
use oso::{Oso, PolarClass};
// 定义用户类型
#[derive(Clone, PolarClass)]
struct User {
#[polar(attribute)]
name: String,
#[polar(attribute)]
roles: Vec<String>,
}
// 定义资源类型
#[derive(Clone, PolarClass)]
struct Document {
#[polar(attribute)]
id: String,
#[polar(attribute)]
owner: String,
}
impl Document {
fn new(id: &str, owner: &str) -> Self {
Document {
id: id.to_string(),
owner: owner.to_string(),
}
}
}
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#"
# 定义角色权限
allow(user: User, "read", doc: Document) if
"reader" in user.roles or
"admin" in user.roles or
user.name = doc.owner;
allow(user: User, "write", doc: Document) if
"writer" in user.roles or
"admin" in user.roles or
user.name = doc.owner;
allow(user: User, "delete", doc: Document) if
"admin" in user.roles or
user.name = doc.owner;
"#)?;
// 创建测试用户
let admin = User {
name: "admin".to_string(),
roles: vec!["admin".to_string()],
};
let writer = User {
name: "writer".to_string(),
roles: vec!["writer".to_string()],
};
let reader = User {
name: "reader".to_string(),
roles: vec!["reader".to_string()],
};
let owner = User {
name: "alice".to_string(),
roles: vec![],
};
let stranger = User {
name: "bob".to_string(),
roles: vec![],
};
// 创建测试文档
let doc = Document::new("123", "alice");
// 测试授权
assert!(oso.is_allowed(admin.clone(), "read", doc.clone())?);
assert!(oso.is_allowed(writer.clone(), "write", doc.clone())?);
assert!(oso.is_allowed(reader.clone(), "read", doc.clone())?);
assert!(oso.is_allowed(owner.clone(), "delete", doc.clone())?);
assert!(!oso.is_allowed(stranger.clone(), "write", doc.clone())?);
println!("所有测试通过!");
Ok(())
}
这个示例展示了如何使用oso-derive宏和Oso库实现基于角色的访问控制:
- 使用
#[derive(PolarClass)]
宏使Rust类型可用于Oso策略 - 使用
#[polar(attribute)]
属性标记应暴露给策略的字段 - 定义角色权限规则(admin、writer、reader)
- 实现资源所有者特殊权限
- 使用
oso.is_allowed()
方法检查权限
Oso还支持更复杂的授权场景,如关系型授权和集合过滤。
1 回复
以下是基于提供的内容整理的完整示例demo:
内容中提供的示例代码
// 1. 添加依赖 (Cargo.toml)
// [dependencies]
// oso-derive = "0.4"
// oso = "0.4"
use oso_derive::*;
use oso::Oso;
// 2. 定义角色和权限
#[derive(PolarClass)]
struct User {
#[polar(attribute)]
roles: Vec<String>,
}
#[derive(PolarClass)]
struct Document {
#[polar(attribute)]
owner_id: i32,
}
// 3. 定义授权策略
fn setup_oso() -> Oso {
let mut oso = Oso::new();
// 注册类型
oso.register_class(User::get_polar_class()).unwrap();
oso.register_class(Document::get_polar_class()).unwrap();
// 加载策略
oso.load_str(r#"
# 定义角色权限
has_permission(user: User, "read", doc: Document) if
doc.owner_id = user.id;
has_permission(user: User, "write", doc: Document) if
"admin" in user.roles;
# RBAC规则
has_role(user: User, role: String) if
role in user.roles;
"#).unwrap();
oso
}
// 4. 使用授权检查
fn main() {
let oso = setup_oso();
let user = User {
id: 1,
roles: vec!["admin".to_string()],
};
let doc = Document {
owner_id: 2,
};
// 检查权限
let is_allowed = oso.is_allowed(user, "write", doc).unwrap();
println!("Can user write document? {}", is_allowed); // true
let is_allowed = oso.is_allowed(user, "read", doc).unwrap();
println!("Can user read document? {}", is_allowed); // false
}
完整示例demo
// Cargo.toml 依赖
// [dependencies]
// oso-derive = "0.4"
// oso = "0.4"
// serde = { version = "1.0", features = ["derive"] }
use oso_derive::*;
use oso::Oso;
use serde::{Serialize, Deserialize};
// 用户结构体
#[derive(PolarClass, Serialize, Deserialize, Clone, Debug)]
struct User {
#[polar(attribute)]
pub id: i32,
#[polar(attribute)]
pub roles: Vec<String>,
#[polar(attribute)]
pub department: String,
}
// 文档资源结构体
#[derive(PolarClass, Serialize, Deserialize, Clone, Debug)]
struct Document {
#[polar(attribute)]
pub owner_id: i32,
#[polar(attribute)]
pub department: String,
#[polar(attribute)]
pub status: String, // "draft", "pending", "published"
}
// 初始化Oso并设置策略
fn setup_oso() -> Oso {
let mut oso = Oso::new();
// 注册自定义类型
oso.register_class(User::get_polar_class()).unwrap();
oso.register_class(Document::get_polar_class()).unwrap();
// 加载策略规则
oso.load_str(r#"
# 基础权限规则
has_permission(user: User, "view", doc: Document) if
doc.owner_id = user.id;
has_permission(user: User, "edit", doc: Document) if
doc.owner_id = user.id and doc.status != "published";
# 部门权限
has_permission(user: User, "view", doc: Document) if
doc.department = user.department and
"department_viewer" in user.roles;
# 管理权限
has_permission(user: User, "delete", doc: Document) if
"admin" in user.roles;
has_permission(user: User, "publish", doc: Document) if
("publisher" in user.roles and doc.department = user.department) or
"admin" in user.roles;
# 工作流权限
has_permission(user: User, "approve", doc: Document) if
doc.status = "pending" and
("approver" in user.roles or "manager" in user.roles) and
doc.department = user.department;
# RBAC角色检查
has_role(user: User, role: String) if
role in user.roles;
"#).unwrap();
oso
}
fn main() {
let oso = setup_oso();
// 创建测试用户
let admin = User {
id: 1,
roles: vec!["admin".to_string()],
department: "IT".to_string(),
};
let publisher = User {
id: 2,
roles: vec!["publisher".to_string(), "department_viewer".to_string()],
department: "Marketing".to_string(),
};
let regular_user = User {
id: 3,
roles: vec!["department_viewer".to_string()],
department: "Marketing".to_string(),
};
// 创建测试文档
let marketing_doc = Document {
owner_id: 2,
department: "Marketing".to_string(),
status: "pending".to_string(),
};
let it_doc = Document {
owner_id: 1,
department: "IT".to_string(),
status: "draft".to_string(),
};
// 权限检查示例
println!("Admin can delete marketing doc? {}",
oso.is_allowed(admin.clone(), "delete", marketing_doc.clone()).unwrap());
println!("Publisher can publish marketing doc? {}",
oso.is_allowed(publisher.clone(), "publish", marketing_doc.clone()).unwrap());
println!("Regular user can view marketing doc? {}",
oso.is_allowed(regular_user.clone(), "view", marketing_doc.clone()).unwrap());
println!("Publisher can approve marketing doc? {}",
oso.is_allowed(publisher.clone(), "approve", marketing_doc.clone()).unwrap());
println!("Regular user can edit IT doc? {}",
oso.is_allowed(regular_user.clone(), "edit", it_doc.clone()).unwrap());
}
/*
预期输出:
Admin can delete marketing doc? true
Publisher can publish marketing doc? true
Regular user can view marketing doc? true
Publisher can approve marketing doc? false
Regular user can edit IT doc? false
*/
这个完整示例展示了:
- 更复杂的用户和文档结构
- 多种权限规则组合(所有权、部门、角色、状态等)
- 实际业务场景中的权限检查
- 清晰的注释说明
- 预期的输出结果
您可以根据实际需求调整用户角色、文档状态和权限规则。