Skip to content

Commit

Permalink
li-engine/lient: improve access-control for api
Browse files Browse the repository at this point in the history
  • Loading branch information
Bean.Wei committed May 11, 2022
1 parent c17ef96 commit 190655e
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 39 deletions.
6 changes: 3 additions & 3 deletions li-engine/ac/ac.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,16 @@ func CheckForView(ctx context.Context, paths ...string) (removes []string, err e
return
}

// CheckForResponse 接口响应的鉴权,执行全部并返需要移除的无权限的字段
func CheckForResponse(ctx context.Context, acmap map[string]AC, fields ...string) (removes []string, err error) {
// CheckForModel 数据层的鉴权,执行全部并返需要移除的无权限的字段
func CheckForModel(ctx context.Context, acmap map[string]AC, action string, fields ...string) (removes []string, err error) {
if len(fields) == 0 {
return
}
g := errgroup.WithCancel(context.Background())
g.GOMAXPROCS(runtime.NumCPU())
ch := make(chan string, len(fields))
for _, field := range fields {
f := acmap["read:"+field]
f := acmap[action+":"+field]
if f == nil {
continue
}
Expand Down
102 changes: 83 additions & 19 deletions li-engine/contrib/lient/template/controller.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,56 @@
{{ define "model/additional/lient-controller" }}
{{ $queryFields := listfield }}
{{ $sortFields := list }}
{{ $acCreateFields := list }}
{{ $acReadFields := list }}
{{ $acUpdateFields := list }}
type (
I{{ $.Name }} struct {
ID {{ $.ID.Type }} {{ with $.Annotations.Fields.StructTag.id }}`{{ . }}`{{ else }}`{{ $.ID.StructTag }}`{{ end }}
{{- range $f := $.Fields }}
{{- $tag := $f.StructTag }}{{ with $tags := $.Annotations.Fields.StructTag }}{{ with index $tags $f.Name }}{{ $tag = . }}{{ end }}{{ end }}
{{ $f.StructField }} {{ if $f.NillableValue }}*{{ end }}{{ $f.Type }} {{ if not $f.Sensitive }}`{{ $tag }}`{{ else }}`json:"-"`{{ end }}
{{- $annotation := $f.Annotations.LiEnt }}
{{- if and $annotation $annotation.Edge }}
{{ $annotation.Edge.StructField }} {{ if ne $f.Type.String $.ID.Type.String }}[]{{ end }}*I{{ $annotation.Edge.Type }} `json:"{{ $annotation.Edge.Name }},omitempty"`
{{- if $annotation }}
{{- if $annotation.Edge }}
{{ $annotation.Edge.StructField }} {{ if ne $f.Type.String $.ID.Type.String }}[]{{ end }}*I{{ $annotation.Edge.Type }} `json:"{{ $annotation.Edge.Name }},omitempty"`
{{- end }}
{{- $quoteFieldName := printf `"%s"` $f.Name }}
{{- if $annotation.DisableCreate }}
{{- $acCreateFields = append $acCreateFields $quoteFieldName }}
{{- if $annotation.Edge }}
{{- $acCreateFields = append $acCreateFields (printf `"%s"` $annotation.Edge.Name) }}
{{- end }}
{{- end }}
{{- if $annotation.DisableRead }}
{{- $acReadFields = append $acReadFields $quoteFieldName }}
{{- if $annotation.Edge }}
{{- $acReadFields = append $acReadFields (printf `"%s"` $annotation.Edge.Name) }}
{{- end }}
{{- end }}
{{- if $annotation.DisableUpdate }}
{{- $acUpdateFields = append $acUpdateFields $quoteFieldName }}
{{- if $annotation.Edge }}
{{- $acUpdateFields = append $acUpdateFields (printf `"%s"` $annotation.Edge.Name) }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- range $e := $.Edges }}
{{ $e.StructField }} {{ if not $e.Unique }}[]{{ end }}*I{{ $e.Type.Name }} {{ with $e.StructTag }}`{{ . }}`{{ end }}
{{- $annotation := $e.Annotations.LiEnt }}
{{- if $annotation }}
{{- $quoteFieldName := printf `"%s"` $e.Name }}
{{- if $annotation.DisableCreate }}
{{- $acCreateFields = append $acCreateFields $quoteFieldName }}
{{- end }}
{{- if $annotation.DisableRead }}
{{- $acReadFields = append $acReadFields $quoteFieldName }}
{{- end }}
{{- if $annotation.DisableUpdate }}
{{- $acUpdateFields = append $acUpdateFields $quoteFieldName }}
{{- end }}
{{- end }}
{{- end }}
}
List{{ $.Name }}Req struct {
Expand Down Expand Up @@ -153,7 +190,6 @@ func NewI{{ $.Name }}(e *{{ $.Name }}, checkAccess ...bool) *I{{ $.Name }} {
return nil
}
if len(checkAccess) > 0 && checkAccess[0] {
{{- $acfields := list }}
{{- $acfieldsSynatx := list }}
{{- range $f := $.Fields }}
{{- if not $f.Sensitive }}
Expand All @@ -169,7 +205,6 @@ func NewI{{ $.Name }}(e *{{ $.Name }}, checkAccess ...bool) *I{{ $.Name }} {
e.{{ $f.StructField }} = nil
{{- end }}
{{- else }}
{{- $acfields = append $acfields (printf `"%s"` $f.Name) }}
{{- if or (contains $f.Type.String "int") (contains $f.Type.String "float") }}
{{- $acfieldsSynatx = append $acfieldsSynatx (printf `e.%s = 0` $f.StructField) }}
{{- else if eq $f.Type.String "string" }}
Expand All @@ -179,6 +214,9 @@ func NewI{{ $.Name }}(e *{{ $.Name }}, checkAccess ...bool) *I{{ $.Name }} {
{{- else }}
{{- $acfieldsSynatx = append $acfieldsSynatx (printf `e.%s = nil` $f.StructField) }}
{{- end }}
{{- if and $annotation $annotation.Edge }}
{{- $acfieldsSynatx = append $acfieldsSynatx (printf `e.Edges.%s = nil` $annotation.Edge.StructField) }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
Expand All @@ -187,19 +225,21 @@ func NewI{{ $.Name }}(e *{{ $.Name }}, checkAccess ...bool) *I{{ $.Name }} {
{{- if and $annotation $annotation.DisableRead }}
e.Edges.{{ $e.StructField }} = nil
{{- else }}
{{- $acfields = append $acfields (printf `"%s"` $e.Name) }}
{{- $acfieldsSynatx = append $acfieldsSynatx (printf `e.Edges.%s = nil` $e.StructField) }}
{{- end }}
{{- end }}
{{- if ne (len $acfields) 0 }}
fields, err := ac.CheckForResponse(context.Background(), {{ $.Package }}ACL, {{ joinx $acfields ", " }})
{{- if ne (len $acReadFields) 0 }}
removes, err := ac.CheckForModel(context.Background(), {{ $.Package }}ACL, "read", {{ joinx $acReadFields ", " }})
if err != nil {
panic(err)
}
if len(fields) > 0 {
fieldsStr := "|" + strings.Join(fields, "|") + "|"
{{- range $i, $af := $acfields }}
if strings.Contains(fieldsStr, "|" + {{ $af }} + "|") {
if len(removes) > 0 {
removesmap := make(map[string]bool, len(removes))
for _, r := range removes {
removesmap[r] = true
}
{{- range $i, $af := $acReadFields }}
if removesmap[{{ $af }}] {
{{ index $acfieldsSynatx $i }}
}
{{- end }}
Expand Down Expand Up @@ -364,12 +404,24 @@ func List{{ $.Name }}Controller(ctx context.Context, req *List{{ $.Name }}Req) (
}

func Create{{ $.Name }}Controller(ctx context.Context, req *Create{{ $.Name }}Req) (err error) {
var removesmap map[string]bool
{{- if ne (len $acCreateFields) 0 }}
removes, err := ac.CheckForModel(ctx, {{ $.Package }}ACL, "create", {{ joinx $acCreateFields ", " }})
if err != nil {
panic(err)
}
if len(removes) > 0 {
for _, r := range removes {
removesmap[r] = true
}
}
{{- end }}
b := DB().{{ $.Name }}.Create()
{{- range $f := $.Fields }}
{{- $annotation := $f.Annotations.LiEnt }}
{{- if and $annotation $annotation.ViewSchema (not $annotation.DisableCreate) }}
{{- if $annotation.Edge }}
if req.{{ $annotation.Edge.StructField }} != nil && {{ $.Name }}AccessControlExecX(ctx, "create:{{ $f.Name }}") {
if req.{{ $annotation.Edge.StructField }} != nil && !removesmap["{{ $f.Name }}"] && !removesmap["{{ $annotation.Edge.Name }}"] {
{{- if eq $f.Type.String $.ID.Type.String }}
b.Set{{ $f.StructField }}(req.{{ $annotation.Edge.StructField }}.ID)
{{- else }}
Expand All @@ -384,7 +436,7 @@ func Create{{ $.Name }}Controller(ctx context.Context, req *Create{{ $.Name }}Re
}
{{- else }}
{{- if $f.Optional }}
if req.{{ $f.StructField }} != nil && {{ $.Name }}AccessControlExecX(ctx, "create:{{ $f.Name }}") {
if req.{{ $f.StructField }} != nil && !removesmap["{{ $f.Name }}"] {
{{- if $f.Type.Nillable }}
b.Set{{ $f.StructField }}(req.{{ $f.StructField }})
{{- else }}
Expand All @@ -401,13 +453,13 @@ func Create{{ $.Name }}Controller(ctx context.Context, req *Create{{ $.Name }}Re
{{- $annotation := $e.Annotations.LiEnt }}
{{- if and $annotation $annotation.ViewSchema (not $annotation.DisableCreate) }}
{{- if $e.Unique }}
if req.{{ $e.StructField }} != nil && {{ $.Name }}AccessControlExecX(ctx, "create:{{ $e.Name }}") {
if req.{{ $e.StructField }} != nil && !removesmap["{{ $e.Name }}"] {
{{- if $e.Field }}
b.Set{{ pascal $e.Field.Name }}(req.{{ $e.StructField }}.ID)
{{- end }}
}
{{- else if not $e.Field }}
if len(req.{{ $e.StructField }}) > 0 && {{ $.Name }}AccessControlExecX(ctx, "create:{{ $e.Name }}") {
if len(req.{{ $e.StructField }}) > 0 && !removesmap["{{ $e.Name }}"] {
b.Add{{ $e.Type.Name }}IDs(func() []{{ $e.Type.ID.Type }} {
ids := make([]{{ $e.Type.ID.Type }}, len(req.{{ $e.StructField }}))
for i, v := range req.{{ $e.StructField }} {
Expand Down Expand Up @@ -456,13 +508,25 @@ func Get{{ $.Name }}Controller(ctx context.Context, req *Get{{ $.Name }}Req) (re
}

func Update{{ $.Name }}Controller(ctx context.Context, req *Update{{ $.Name }}Req) (err error) {
var removesmap map[string]bool
{{- if ne (len $acUpdateFields) 0 }}
removes, err := ac.CheckForModel(ctx, {{ $.Package }}ACL, "update", {{ joinx $acUpdateFields ", " }})
if err != nil {
panic(err)
}
if len(removes) > 0 {
for _, r := range removes {
removesmap[r] = true
}
}
{{- end }}
b := DB().{{ $.Name }}.UpdateOneID(req.ID)
{{- range $f := $.Fields }}
{{- if not $f.Sensitive }}
{{- $annotation := $f.Annotations.LiEnt }}
{{- if and $annotation $annotation.ViewSchema (not $annotation.DisableUpdate) }}
{{- if $annotation.Edge }}
if req.{{ $annotation.Edge.StructField }} != nil && {{ $.Name }}AccessControlExecX(ctx, "update:{{ $f.Name }}") {
if req.{{ $annotation.Edge.StructField }} != nil && !removesmap["{{ $f.Name }}"] && !removesmap["{{ $annotation.Edge.Name }}"] {
{{- if eq $f.Type.String $.ID.Type.String }}
b.Set{{ $f.StructField }}(req.{{ $annotation.Edge.StructField }}.ID)
{{- else }}
Expand All @@ -476,7 +540,7 @@ func Update{{ $.Name }}Controller(ctx context.Context, req *Update{{ $.Name }}Re
{{- end }}
}
{{- else }}
if req.{{ $f.StructField }} != nil && {{ $.Name }}AccessControlExecX(ctx, "update:{{ $f.Name }}") {
if req.{{ $f.StructField }} != nil && !removesmap["{{ $f.Name }}"] {
{{- if $f.Type.Nillable }}
b.Set{{ $f.StructField }}(req.{{ $f.StructField }})
{{- else }}
Expand All @@ -491,13 +555,13 @@ func Update{{ $.Name }}Controller(ctx context.Context, req *Update{{ $.Name }}Re
{{- $annotation := $e.Annotations.LiEnt }}
{{- if and $annotation $annotation.ViewSchema (not $annotation.DisableUpdate) }}
{{- if $e.Unique }}
if req.{{ $e.StructField }} != nil && {{ $.Name }}AccessControlExecX(ctx, "update:{{ $e.Name }}") {
if req.{{ $e.StructField }} != nil && !removesmap["{{ $e.Name }}"] {
{{- if $e.Field }}
b.Set{{ pascal $e.Field.Name }}(req.{{ $e.StructField }}.ID)
{{- end }}
}
{{- else if not $e.Field }}
if req.{{ $e.StructField }} != nil && {{ $.Name }}AccessControlExecX(ctx, "update:{{ $e.Name }}") {
if req.{{ $e.StructField }} != nil && !removesmap["{{ $e.Name }}"] {
b.Clear{{ $e.StructField }}().Add{{ $e.Type.Name }}IDs(func() []{{ $e.Type.ID.Type }} {
ids := make([]{{ $e.Type.ID.Type }}, len(req.{{ $e.StructField }}))
for i, v := range req.{{ $e.StructField }} {
Expand Down
17 changes: 0 additions & 17 deletions li-engine/contrib/lient/template/view.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -221,21 +221,4 @@ func init() {
{{ $.Package }}ACL, _ = rf.Call([]reflect.Value{})[0].Interface().(map[string]ac.AC)
}
}

func {{ $.Name }}AccessControlExec(ctx context.Context, key string) (pass bool, err error) {
f := {{ $.Package }}ACL[key]
if f != nil {
return f(ctx)
}
return true, nil
}

func {{ $.Name }}AccessControlExecX(ctx context.Context, key string) (pass bool) {
var err error
pass, err = {{ $.Name }}AccessControlExec(ctx, key)
if err != nil {
panic(err)
}
return
}
{{ end }}

0 comments on commit 190655e

Please sign in to comment.