5 个不稳定版本

0.3.2 2024年7月31日
0.3.1 2024年7月31日
0.2.2 2024年7月19日
0.1.0 2024年7月12日

#1139数据库接口

Download history 84/week @ 2024-07-10 410/week @ 2024-07-17 15/week @ 2024-07-24 188/week @ 2024-07-31

每月下载量 613

MIT 许可证

52KB
1K SLoC

spicedb-rust

一个基于官方 gRPC API 构建的 SpiceDB 的有观点客户端,避免了在 Rust 中使用 gRPC 的缺点。

免责声明

API 仍不稳定,可能存在破坏性更改

API

API 提供了所有 gRPC 请求的构建器接口,利用泛型 trait 类型系统减少了部分请求构建的样板代码和潜在的错误/打字错误。

一些最常见的请求直接作为函数暴露在 Client 结构中,例如 lookup_resources 直接到 Vec<R::Id> 或直接到 check_permissionbool

作为构建器接口的替代,客户端还直接暴露了所有参数一次的方法,如果您打算使用即将推出的 mock 功能,以避免在测试中运行本地的 SpiceDB 实例,建议您这样做。

关于 impl Trait 参数在 SpiceDBClient 上的实现,这些参数都已通过泛型或仅为 String&str 删除。这种轻微的 QoL 丢失允许 mockall 构建 MockSpiceDBClient

类型系统

此 crate 的类型系统允许定义 Rust 结构体,其 traits 反映了导入到 SpiceDB 中的架构。这减少了在开发过程中键入原始字符串时可能出现的打字错误和其他错误,并使得使用一些编译时检查构建相当复杂的 gRPC 请求变得更容易。

优点

  • 永远不会因为为关系或权限传递错误的 String 值而出错
  • 永远不会尝试创建不属于您的实体之一的关系
  • 通过将您的授权模式集中到 Rust 库 crate 中,轻松地在多个服务间共享您的授权模式
  • String 类型自动转换为您的 id 类型,如 u32Uuid

缺点

  • 有一些样板代码

我不喜欢类型系统,能否直接使用原始 gRPC API?

可以的。 SpiceDBClient 提供了获取底层 tonic 客户端的方法,而 spicedb 模块导出了所有 protobuf 类型。根据个人经验,这并不有趣。

示例

让我们看看以下 SpiceDB 模式

definition user {}

definition document {
    relation reader: user | user:*
    relation writer: user
    
    permission read = reader + writer
    permission write = writer
}

我们有 2 个实体,UserDocument。这是样板代码

struct User;

impl Entity for User {
    type Relations = NoRelations;
    type Id = Uuid;

    fn object_type() -> &'static str {
        "user"
    }
}

struct MyActor(Uuid);

impl Actor for MyActor {
    fn to_subject(&self) -> SubjectReference {
        subject_reference_raw(self.0, User::object_type(), None::<String>)
    }
}

struct Document;

#[derive(IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub enum DocumentPermission {
    Read,
    Write,
}

impl Entity for Document {
    type Relations = DocumentRelation;
    type Id = String;

    fn object_type() -> &'static str {
        "document"
    }
}

#[derive(IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub enum DocumentRelation {
    Reader,
    Writer,
}

impl Resource for Document {
    type Permissions = DocumentPermission;
}

注意: 由于 strum crate 中的 IntoStaticStr 宏,现在已经移除了 RelationsPermissions 的样板代码,此 crate 也重新导出了它。

现在的类型系统使得无法检查不存在的权限,或创建不支持实体的关系。

注意: 我不知道是否可以通过类型限制关系的 Subject 部分,我还没有走过这条路,而且我现在还不需要,我会很好奇是否有简单的方法来做这件事。

现在让我们创建一些关系并检查一些权限!

let client = SpiceDBClient::new("https://127.0.0.1:50051".to_owned(), "randomkey")
    .await?;
let user_id = Uuid::now_v7();
let relationships = [
    relationship_update::<User, Document>(
        RelationshipOperation::Touch,
        user_id,
        None,
        "homework",
        DocumentRelation::Writer,
    ),
    wildcard_relationship_update::<User, Document>(
        RelationshipOperation::Touch,
        "manga",
        DocumentRelation::Reader,
    ),
];
let token = client
    .create_relationships(relationships, [])
    .await
    .unwrap();
let actor = MyActor(user_id);
let authorized = client.check_permission_at::<_, Document>(
    &actor,
    "homework",
    DocumentPermission::Write,
    token.clone(),
)
.await?;

模拟

启用 mock 功能,以使用由 mockall 生成的客户端。所有公共接口都将按预期工作,但请求构建器接口除外,因为它们没有被模拟,如果您目前正在使用这些接口,您必须针对 SpiceDB 的真实实例进行测试。代码仍然可以编译,但是任何测试到这些代码行的测试都将崩溃。

依赖关系

~6–16MB
~186K SLoC