123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- package perm
- import (
- "crypto/md5"
- "errors"
- "fmt"
- "net/http"
- "reflect"
- "strings"
- "time"
- "github.com/iancoleman/strcase"
- "github.com/jinzhu/inflection"
- "github.com/ory/ladon"
- "github.com/ory/ladon/manager/memory"
- "github.com/sunfmin/reflectutils"
- "gorm.io/gorm"
- )
- const (
- Allowed = ladon.AllowAccess
- Denied = ladon.DenyAccess
- Anything = "*"
- Anybody = "*"
- Anonymous = "anonymous"
- )
- var PermissionDenied = errors.New("permission denied")
- type Context = ladon.Context
- type Conditions = ladon.Conditions
- type SubjectsFunc func(r *http.Request) []string
- type ContextFunc func(r *http.Request, objs []interface{}) Context
- type DBPolicy interface {
- LoadDBPolicies(db *gorm.DB, startFrom *time.Time) ([]*PolicyBuilder, []*PolicyBuilder)
- }
- type permRNer interface {
- PermissionRN() []string
- }
- func ToPermissionRN(v interface{}) []string {
- if pr, ok := v.(permRNer); ok {
- return pr.PermissionRN()
- }
- typeName := fmt.Sprint(reflect.TypeOf(v))
- ss := strings.Split(typeName, ".")
- typeName = ss[len(ss)-1]
- typeName = strings.NewReplacer("*", "", ".", "-").Replace(typeName)
- typeName = strcase.ToSnake(inflection.Plural(typeName))
- id, err := reflectutils.Get(v, "ID")
- if err == nil && len(fmt.Sprint(id)) > 0 && fmt.Sprint(id) != "0" {
- return []string{typeName, fmt.Sprint(id)}
- }
- return []string{typeName}
- }
- type Builder struct {
- policies []*PolicyBuilder
- ladon *ladon.Ladon
- subjectsFunc SubjectsFunc
- contextFunc ContextFunc
- dbPolicyModel DBPolicy
- }
- func New() *Builder {
- return &Builder{
- ladon: &ladon.Ladon{
- Manager: memory.NewMemoryManager(),
- Matcher: &PathMatcher{},
- },
- }
- }
- func (b *Builder) Policies(ps ...*PolicyBuilder) (r *Builder) {
- b.policies = ps
- for _, p := range b.policies {
- if p.policy.ID == "" {
- p.policy.ID = fmt.Sprintf("%x", md5.Sum(p.Json()))
- }
- err := b.ladon.Manager.Create(p.policy)
- if err != nil {
- panic(err)
- }
- }
- return b
- }
- func (b *Builder) SubjectsFunc(v SubjectsFunc) (r *Builder) {
- b.subjectsFunc = v
- return b
- }
- func (b *Builder) ContextFunc(v ContextFunc) (r *Builder) {
- b.contextFunc = v
- return b
- }
- func (b *Builder) EnableDBPolicy(db *gorm.DB, dbPolicyModel DBPolicy, loadDuration time.Duration) (r *Builder) {
- if dbPolicyModel == nil {
- b.dbPolicyModel = DefaultDBPolicy{}
- } else {
- b.dbPolicyModel = dbPolicyModel
- }
- go b.loopLoadDBPolicies(db, loadDuration)
- return b
- }
- func (b *Builder) UpdatePolicies(toUpdate ...*PolicyBuilder) {
- for _, p := range toUpdate {
- b.ladon.Manager.Update(p.policy)
- }
- }
- func (b *Builder) DeletePolicies(toDelete ...*PolicyBuilder) {
- for _, p := range toDelete {
- b.ladon.Manager.Delete(p.GetID())
- }
- }
- func (b *Builder) LoadDBPoliciesToMemory(db *gorm.DB, startFrom *time.Time) {
- toUpdate, toDelete := b.dbPolicyModel.LoadDBPolicies(db, startFrom)
- b.DeletePolicies(toDelete...)
- b.UpdatePolicies(toUpdate...)
- if Verbose {
- b.printPolices()
- }
- }
- func (b *Builder) loopLoadDBPolicies(db *gorm.DB, duration time.Duration) {
- now := time.Now()
- b.LoadDBPoliciesToMemory(db, nil)
- for next := range time.Tick(duration) {
- b.LoadDBPoliciesToMemory(db, &now)
- now = next
- }
- }
- func (b *Builder) printPolices() {
- allp, _ := b.ladon.Manager.GetAll(100, 0)
- for _, p := range allp {
- fmt.Printf("%+v \n", p)
- }
- }
|