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(())
}

示例解释

  1. 定义模型:我们定义了UserDocument结构体,并使用PolarClass派生宏使它们可用于Oso策略。

  2. 策略规则:我们定义了三条授权规则:

    • 管理员可以读取任何文档
    • 文档所有者可以读取自己的文档
    • 任何人都可以读取公开文档
  3. 测试授权:我们创建了几个测试用户和文档,然后使用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(())
}

这个扩展示例展示了:

  1. 使用枚举类型定义角色和文章状态
  2. 实现更复杂的RBAC策略
  3. 基于资源状态的权限控制
  4. 多种操作类型(查看、编辑、发布)的权限管理

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(())
}

代码说明

  1. 数据结构定义

    • User结构体表示系统用户,包含ID、角色和允许访问时间段
    • Document结构体表示文档资源,包含ID、所有者ID、是否公开和创建时间
  2. 自定义函数

    • time_in_range函数检查当前时间是否在允许访问的时间段内
  3. oso初始化

    • 创建oso实例并注册自定义类型
    • 注册自定义函数和常量
  4. 策略规则

    • 管理员拥有所有权限
    • 文档所有者可以编辑自己的文档
    • 公开文档可被所有人读取
    • 只能在允许的时间段内访问
  5. 测试用例

    • 创建管理员和普通用户
    • 创建公开和私有文档
    • 进行各种权限检查
    • 演示批量授权检查
    • 展示数据过滤功能

运行结果示例

程序运行后会输出类似以下结果:

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中的主要功能,包括策略定义、权限检查、批量授权和数据过滤等。

回到顶部