golang基于Zanzibar论文实现细粒度授权系统插件库openfgaCNCF的使用

Golang基于Zanzibar论文实现细粒度授权系统插件库OpenFGA(CNCF)的使用

OpenFGA是一个高性能且灵活的授权/权限引擎,专为开发者设计,灵感来源于Google的Zanzibar论文。它旨在帮助开发者轻松建模应用程序权限,并将细粒度授权集成到应用中。

OpenFGA简介

OpenFGA支持内存数据存储用于快速开发,以及可插拔的数据库模块。目前支持PostgreSQL 14+、MySQL 8和SQLite(目前处于测试阶段)。

它提供HTTP API和gRPC API,并有多种语言的SDK支持,包括Java、Node.js/JavaScript、GoLang、Python和.NET

安装OpenFGA

使用Docker安装

docker pull openfga/openfga
docker run -p 8080:8080 -p 3000:3000 openfga/openfga run

使用Docker Compose安装

  1. 下载docker-compose.yaml文件:
curl -LO https://openfga.dev/docker-compose.yaml
  1. 启动服务:
docker compose up

使用Homebrew安装

brew install openfga

从源码构建

使用go install

export PATH=$PATH:$(go env GOBIN)
go install github.com/openfga/openfga/cmd/openfga
./openfga run

使用go build

git clone https://github.com/openfga/openfga.git && cd openfga
go build -o ./openfga ./cmd/openfga
./openfga run

验证安装

创建OpenFGA存储来验证安装:

curl -X POST 'localhost:8080/stores' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "openfga-demo"
}'

成功响应示例:

{
  "id": "01G3EMTKQRKJ93PFVDA1SJHWD2",
  "name": "openfga-demo",
  "created_at": "2022-05-19T17:11:12.888680Z",
  "updated_at": "2022-05-19T17:11:12.888680Z"
}

使用Go SDK示例

以下是一个完整的Go示例,展示如何使用OpenFGA Go SDK:

package main

import (
	"context"
	"fmt"
	"log"

	openfga "github.com/openfga/go-sdk"
	"github.com/openfga/go-sdk/client"
)

func main() {
	// 初始化OpenFGA客户端配置
	configuration, err := client.NewConfiguration(client.Configuration{
		ApiScheme: "http",
		ApiHost:   "localhost:8080",
	})
	if err != nil {
		log.Fatal(err)
	}

	// 创建OpenFGA客户端
	fgaClient := client.NewAPIClient(configuration)

	// 创建存储
	store, _, err := fgaClient.OpenFgaApi.CreateStore(context.Background()).Body(client.ClientCreateStoreRequest{
		Name: "go-sdk-demo",
	}).Execute()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Created store with id: %s\n", store.Id)

	// 定义授权模型
	model := client.ClientWriteAuthorizationModelRequest{
		TypeDefinitions: []openfga.TypeDefinition{
			{
				Type: "user",
			},
			{
				Type: "document",
				Relations: &map[string]openfga.Userset{
					"reader": {
						This: &map[string]interface{}{},
					},
					"writer": {
						This: &map[string]interface{}{},
					},
					"owner": {
						This: &map[string]interface{}{},
					},
				},
				Metadata: &openfga.Metadata{
					Relations: &map[string]openfga.RelationMetadata{
						"reader": {
							DirectlyRelatedUserTypes: &[]openfga.RelationReference{
								{Type: "user"},
							},
						},
						"writer": {
							DirectlyRelatedUserTypes: &[]openfga.RelationReference{
								{Type: "user"},
							},
						},
						"owner": {
							DirectlyRelatedUserTypes: &[]openfga.RelationReference{
								{Type: "user"},
							},
						},
					},
				},
			},
		},
		SchemaVersion: "1.1",
	}

	// 写入授权模型
	authModel, _, err := fgaClient.OpenFgaApi.WriteAuthorizationModel(context.Background()).Body(model).Execute()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Created authorization model with id: %s\n", authModel.AuthorizationModelId)

	// 写入关系元组
	_, err = fgaClient.OpenFgaApi.Write(context.Background()).Body(client.ClientWriteRequest{
		Writes: &[]client.ClientTupleKey{
			{
				User:     "user:anne",
				Relation: "owner",
				Object:   "document:1",
			},
			{
				User:     "user:anne",
				Relation: "writer",
				Object:   "document:1",
			},
		},
	}).Execute()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Successfully wrote tuples")

	// 检查权限
	check, _, err := fgaClient.OpenFgaApi.Check(context.Background()).Body(client.ClientCheckRequest{
		User:     "user:anne",
		Relation: "reader",
		Object:   "document:1",
	}).Execute()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Check result: %v\n", check.Allowed)
}

生产环境注意事项

OpenFGA核心服务自2021年12月起已在Auth0 FGA生产环境中使用。内存存储适配器仅用于开发目的,不建议在生产环境中使用。

社区支持

OpenFGA有一个活跃的社区,定期举行社区会议讨论项目发展和收集反馈。


更多关于golang基于Zanzibar论文实现细粒度授权系统插件库openfgaCNCF的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang基于Zanzibar论文实现细粒度授权系统插件库openfgaCNCF的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


基于Zanzibar论文的细粒度授权系统:OpenFGA与Golang实现

OpenFGA简介

OpenFGA是由Auth0(现Okta)开发并贡献给CNCF的开源授权系统,基于Google Zanzibar论文设计。它提供了一种灵活、高性能的细粒度授权解决方案,特别适合现代分布式系统。

OpenFGA核心概念

  1. 授权模型(Authorization Model):定义对象类型和它们之间的关系
  2. 元组(Tuples):存储具体的关系数据
  3. 检查(Check):验证用户是否有权限
  4. 列表(List):列出用户有权限的对象

Golang中使用OpenFGA

1. 安装OpenFGA SDK

go get github.com/openfga/go-sdk

2. 基本使用示例

package main

import (
	"context"
	"fmt"
	openfga "github.com/openfga/go-sdk"
	"github.com/openfga/go-sdk/client"
)

func main() {
	// 初始化OpenFGA客户端
	configuration, err := client.NewConfiguration(client.Configuration{
		ApiScheme: "http",
		ApiHost:   "localhost:8080",
	})
	if err != nil {
		panic(err)
	}

	fgaClient := client.NewSdkClient(&configuration)

	// 创建授权模型
	model := openfga.WriteAuthorizationModelRequest{
		TypeDefinitions: []openfga.TypeDefinition{
			{
				Type: "document",
				Relations: map[string]openfga.Userset{
					"reader": {
						This: &map[string]interface{}{},
					},
					"writer": {
						This: &map[string]interface{}{},
					},
					"owner": {
						This: &map[string]interface{}{},
					},
				},
			},
		},
	}

	response, err := fgaClient.WriteAuthorizationModel(context.Background()).Body(model).Execute()
	if err != nil {
		panic(err)
	}

	fmt.Printf("Authorization model created with ID: %s\n", *response.AuthorizationModelId)

	// 写入关系元组
	tuples := []openfga.TupleKey{
		{
			User:     "user:alice",
			Relation: "owner",
			Object:   "document:1",
		},
		{
			User:     "user:bob",
			Relation: "reader",
			Object:   "document:1",
		},
	}

	_, err = fgaClient.Write(context.Background()).Body(openfga.WriteRequest{
		Writes: &tuples,
	}).Execute()
	if err != nil {
		panic(err)
	}

	// 检查权限
	checkResponse, err := fgaClient.Check(context.Background()).Body(openfga.CheckRequest{
		User:     "user:bob",
		Relation: "reader",
		Object:   "document:1",
	}).Execute()
	if err != nil {
		panic(err)
	}

	fmt.Printf("Has permission: %v\n", *checkResponse.Allowed)
}

3. 高级功能实现

3.1 自定义关系

// 在模型中定义自定义关系
relations := map[string]openfga.Userset{
	"viewer": {
		Union: &openfga.Usersets{
			Child: []openfga.Userset{
				{This: &map[string]interface{}{}},
				{ComputedUserset: &openfga.ObjectRelation{
					Object:   openfga.PtrString(""),
					Relation: openfga.PtrString("editor"),
				}},
			},
		},
	},
}

3.2 批量检查权限

batchCheckResponse, err := fgaClient.BatchCheck(context.Background()).Body(openfga.BatchCheckRequest{
	Checks: []openfga.CheckRequest{
		{
			User:     "user:alice",
			Relation: "owner",
			Object:   "document:1",
		},
		{
			User:     "user:bob",
			Relation: "reader",
			Object:   "document:1",
		},
	},
}).Execute()

3.3 列出用户有权限的对象

listResponse, err := fgaClient.ListObjects(context.Background()).Body(openfga.ListObjectsRequest{
	User:     "user:bob",
	Relation: "reader",
	Type:     "document",
}).Execute()

实际应用场景

  1. SaaS多租户系统:管理租户间和租户内的资源访问
  2. 文档协作平台:控制文档的查看、编辑权限
  3. 微服务架构:服务间API调用的细粒度授权

性能优化建议

  1. 使用OpenFGA的本地缓存功能
  2. 批量操作代替单个操作
  3. 合理设计授权模型,避免过于复杂的嵌套关系
  4. 考虑使用OpenFGA的watch API实时更新

部署方案

OpenFGA支持多种部署方式:

  1. Docker容器:快速本地开发和测试
  2. Kubernetes:生产环境部署
  3. 托管服务:Auth0提供的托管OpenFGA服务

总结

OpenFGA基于Zanzibar论文的设计,提供了强大的细粒度授权能力。通过Golang SDK可以方便地集成到现有系统中。其灵活的授权模型和高效的关系检查机制使其成为现代分布式系统授权的理想选择。

回到顶部