From 789241364c58ef2d4ffb119595c0ed41e7a7bbb8 Mon Sep 17 00:00:00 2001 From: WintBit <68735689+WinterOfBit@users.noreply.github.com> Date: Sat, 29 Jul 2023 19:24:38 +0800 Subject: [PATCH] feat: support Casdoor storage API (#594) * feat: Casdoor storage API * chore: fmt casdoor.go using gofumpt * feat: add global casdoor config variables --- casdoor/adapter.go | 8 ++-- casdoor/resource_adaptor.go | 38 +++++++++++++++++++ go.mod | 2 +- go.sum | 4 +- storage/casdoor.go | 75 +++++++++++++++++++++++++++++++++++++ storage/storage.go | 28 ++++++++++++++ storage/storage_test.go | 63 +++++++++++++++++++++++++++++-- util/string.go | 6 +++ 8 files changed, 215 insertions(+), 9 deletions(-) create mode 100644 casdoor/resource_adaptor.go create mode 100644 storage/casdoor.go create mode 100644 storage/storage.go diff --git a/casdoor/adapter.go b/casdoor/adapter.go index 34c9bf1..fc3de3f 100644 --- a/casdoor/adapter.go +++ b/casdoor/adapter.go @@ -23,8 +23,9 @@ import ( ) var ( - adapter *Adapter = nil - CasdoorOrganization string + adapter *Adapter = nil + Organization string + Application string ) type Session struct { @@ -41,7 +42,8 @@ func InitCasdoorAdapter() { adapter = NewAdapter(beego.AppConfig.String("driverName"), beego.AppConfig.String("dataSourceName"), beego.AppConfig.String("casdoorDbName")) - CasdoorOrganization = beego.AppConfig.String("casdoorOrganization") + Organization = beego.AppConfig.String("casdoorOrganization") + Application = beego.AppConfig.String("casdoorApplication") } // Adapter represents the MySQL adapter for policy storage. diff --git a/casdoor/resource_adaptor.go b/casdoor/resource_adaptor.go new file mode 100644 index 0000000..6ad2cce --- /dev/null +++ b/casdoor/resource_adaptor.go @@ -0,0 +1,38 @@ +package casdoor + +import ( + "fmt" + + "github.com/astaxie/beego" + "github.com/casbin/casibase/util" + "github.com/casdoor/casdoor-go-sdk/casdoorsdk" +) + +func ListResources(prefix string) ([]*casdoorsdk.Resource, error) { + prefix = util.GetIdFromOwnerAndName(fmt.Sprintf("/resource/%s/%s/casibase", + beego.AppConfig.String("casdoorOrganization"), + beego.AppConfig.String("casdoorApplication")), prefix) + + result := make([]*casdoorsdk.Resource, 0) + err := adapter.Engine.Where("name like ?", prefix+"%").Find(&result) + if err != nil { + return nil, err + } + + return result, nil +} + +func GetResource(key string) (*casdoorsdk.Resource, error) { + id := fmt.Sprintf("/resource/%s/%s/casibase/%s", Organization, Application, key) + resource := casdoorsdk.Resource{Owner: Organization, Name: id} + existed, err := adapter.Engine.Get(&resource) + if err != nil { + return nil, err + } + + if existed { + return &resource, nil + } else { + return nil, fmt.Errorf("resource %s not found", key) + } +} diff --git a/go.mod b/go.mod index 4f56cfa..29531c4 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible github.com/astaxie/beego v1.12.3 github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect - github.com/casdoor/casdoor-go-sdk v0.9.1 + github.com/casdoor/casdoor-go-sdk v0.25.0 github.com/danaugrs/go-tsne/tsne v0.0.0-20220306155740-2250969e057f github.com/go-sql-driver/mysql v1.6.0 github.com/google/uuid v1.3.0 diff --git a/go.sum b/go.sum index 3a93fa2..3d2d7e9 100644 --- a/go.sum +++ b/go.sum @@ -705,8 +705,8 @@ github.com/calebcase/tmpfile v1.0.3 h1:BZrOWZ79gJqQ3XbAQlihYZf/YCV0H4KPIdM5K5oMp github.com/calebcase/tmpfile v1.0.3/go.mod h1:UAUc01aHeC+pudPagY/lWvt2qS9ZO5Zzof6/tIUzqeI= github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/casdoor/casdoor-go-sdk v0.9.1 h1:z+5nJ4IvP9cNUodLf8wS42AYtDoUCvN6McRB5M+1SAQ= -github.com/casdoor/casdoor-go-sdk v0.9.1/go.mod h1:MBed3ISHQfXTtoOCAk5T8l5lt4wFvsyynrw0awggydY= +github.com/casdoor/casdoor-go-sdk v0.25.0 h1:hrx10mgpLgWqNsgFKQN/ljJsnD1i0cytW+S+2XxmxyQ= +github.com/casdoor/casdoor-go-sdk v0.25.0/go.mod h1:MBed3ISHQfXTtoOCAk5T8l5lt4wFvsyynrw0awggydY= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= diff --git a/storage/casdoor.go b/storage/casdoor.go new file mode 100644 index 0000000..3439fc0 --- /dev/null +++ b/storage/casdoor.go @@ -0,0 +1,75 @@ +package storage + +import ( + "fmt" + "io" + "net/http" + "time" + + "github.com/astaxie/beego" + "github.com/casbin/casibase/casdoor" + "github.com/casbin/casibase/util" + "github.com/casdoor/casdoor-go-sdk/casdoorsdk" +) + +type casdoorClient struct { + Storage +} + +func NewCasdoorStorage() Storage { + return &casdoorClient{} +} + +func (s *casdoorClient) Get(key string) (io.ReadCloser, error) { + res, err := casdoor.GetResource(key) + if err != nil { + return nil, err + } + + response, err := http.Get(res.Url) + if err != nil { + return nil, err + } + + return response.Body, nil +} + +func (s *casdoorClient) Put(user, key string, bytes []byte) error { + _, _, err := casdoorsdk.UploadResource(user, "Casibase", "Casibase", + fmt.Sprintf("/resource/%s/%s/%s", + casdoor.Organization, casdoor.Application, key), + bytes) + if err != nil { + return err + } + return nil +} + +func (s *casdoorClient) Delete(key string) error { + _, err := casdoorsdk.DeleteResource(util.GetIdFromOwnerAndName(fmt.Sprintf("/resource/%s/%s/casibase", + beego.AppConfig.String("casdoorOrganization"), + beego.AppConfig.String("casdoorApplication")), key)) + if err != nil { + return err + } + return nil +} + +func (s *casdoorClient) List(prefix string) ([]*Object, error) { + res, err := casdoor.ListResources(prefix) + if err != nil { + return nil, err + } + + result := make([]*Object, 0) + for _, r := range res { + created, _ := time.Parse(time.RFC3339, r.CreatedTime) + result = append(result, &Object{ + Key: util.GetNameFromIdNoCheck(r.Name), + LastModified: &created, + Storage: s, + }) + } + + return result, nil +} diff --git a/storage/storage.go b/storage/storage.go new file mode 100644 index 0000000..d82d16c --- /dev/null +++ b/storage/storage.go @@ -0,0 +1,28 @@ +package storage + +import ( + "io" + "time" +) + +type Storage interface { + Get(key string) (io.ReadCloser, error) + Put(user, key string, bytes []byte) error + Delete(key string) error + List(prefix string) ([]*Object, error) +} + +type Object struct { + Key string + LastModified *time.Time + Storage Storage +} + +func NewStorageProvider(provider string) Storage { + switch provider { + case "casdoor": + return NewCasdoorStorage() + default: + return nil + } +} diff --git a/storage/storage_test.go b/storage/storage_test.go index f20bc4f..c03108d 100644 --- a/storage/storage_test.go +++ b/storage/storage_test.go @@ -15,13 +15,70 @@ //go:build !skipCi // +build !skipCi -package storage +package storage_test -import "testing" +import ( + "io" + "testing" + + "github.com/casbin/casibase/casdoor" + "github.com/casbin/casibase/controllers" + "github.com/casbin/casibase/storage" +) func TestStorage(t *testing.T) { - _, err := ListObjects("casibase", "") + _, err := storage.ListObjects("casibase", "") if err != nil { panic(err) } } + +func TestCasdoor(t *testing.T) { + controllers.InitAuthConfig() + casdoor.InitCasdoorAdapter() + s := storage.NewCasdoorStorage() + + // Test Put + err := s.Put("admin", "test", []byte("test")) + if err != nil { + t.Error(err) + } + + // Test List + objs, err := s.List("admin") + if err != nil { + t.Error(err) + } + + for _, obj := range objs { + t.Log(obj) + } + + // Test Get + in, err := s.Get("test") + if err != nil { + t.Error(err) + } + + bytes, err := io.ReadAll(in) + if err != nil { + t.Error(err) + } + + t.Log(string(bytes)) + + // Test Delete + err = s.Delete("test") + if err != nil { + t.Error(err) + } + + objs, err = s.List("test") + if err != nil { + t.Error(err) + } + + for _, obj := range objs { + t.Log(obj) + } +} diff --git a/util/string.go b/util/string.go index 110444f..ac67e3d 100644 --- a/util/string.go +++ b/util/string.go @@ -93,6 +93,12 @@ func GetOwnerAndNameFromId3New(id string) (string, string, string) { return tokens[0], tokens[1], tokens[2] } +func GetNameFromIdNoCheck(id string) string { + tokens := strings.Split(id, "/") + + return tokens[len(tokens)-1] +} + func GetIdFromOwnerAndName(owner string, name string) string { return fmt.Sprintf("%s/%s", owner, name) }