forked from casdoor/casdoor
feat: Enable ABAC support in /api/enforce and /api/batch-enforce
This commit is contained in:
@@ -57,7 +57,9 @@ func (c *ApiController) Enforce() {
|
||||
return
|
||||
}
|
||||
|
||||
var request []string
|
||||
// Accept both plain string arrays (["alice","data1","read"]) and mixed arrays
|
||||
// with JSON objects ([{"DivisionGuid":"x"}, "resource", "read"]) for ABAC support.
|
||||
var request []interface{}
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &request)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -74,8 +76,8 @@ func (c *ApiController) Enforce() {
|
||||
res := []bool{}
|
||||
keyRes := []string{}
|
||||
|
||||
// type transformation
|
||||
interfaceRequest := util.StringToInterfaceArray(request)
|
||||
// Convert elements: JSON-object strings and maps become anonymous structs for ABAC.
|
||||
interfaceRequest := util.InterfaceToEnforceArray(request)
|
||||
|
||||
enforceResult, err := enforcer.Enforce(interfaceRequest...)
|
||||
if err != nil {
|
||||
@@ -197,7 +199,8 @@ func (c *ApiController) BatchEnforce() {
|
||||
return
|
||||
}
|
||||
|
||||
var requests [][]string
|
||||
// Accept both string arrays and mixed arrays with JSON objects for ABAC support.
|
||||
var requests [][]interface{}
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &requests)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -214,8 +217,8 @@ func (c *ApiController) BatchEnforce() {
|
||||
res := [][]bool{}
|
||||
keyRes := []string{}
|
||||
|
||||
// type transformation
|
||||
interfaceRequests := util.StringToInterfaceArray2d(requests)
|
||||
// Convert elements: JSON-object strings and maps become anonymous structs for ABAC.
|
||||
interfaceRequests := util.InterfaceToEnforceArray2d(requests)
|
||||
|
||||
enforceResult, err := enforcer.BatchEnforce(interfaceRequests)
|
||||
if err != nil {
|
||||
|
||||
@@ -357,26 +357,27 @@ func removePolicies(permission *Permission) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func Enforce(permission *Permission, request []string, permissionIds ...string) (bool, error) {
|
||||
func Enforce(permission *Permission, request []interface{}, permissionIds ...string) (bool, error) {
|
||||
enforcer, err := getPermissionEnforcer(permission, permissionIds...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// type transformation
|
||||
interfaceRequest := util.StringToInterfaceArray(request)
|
||||
// Convert each element: JSON-object strings and maps become anonymous structs
|
||||
// so Casbin can evaluate ABAC rules with dot-notation (e.g. r.sub.DivisionGuid).
|
||||
interfaceRequest := util.InterfaceToEnforceArray(request)
|
||||
|
||||
return enforcer.Enforce(interfaceRequest...)
|
||||
}
|
||||
|
||||
func BatchEnforce(permission *Permission, requests [][]string, permissionIds ...string) ([]bool, error) {
|
||||
func BatchEnforce(permission *Permission, requests [][]interface{}, permissionIds ...string) ([]bool, error) {
|
||||
enforcer, err := getPermissionEnforcer(permission, permissionIds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// type transformation
|
||||
interfaceRequests := util.StringToInterfaceArray2d(requests)
|
||||
// Convert each element in every row for ABAC support.
|
||||
interfaceRequests := util.InterfaceToEnforceArray2d(requests)
|
||||
|
||||
return enforcer.BatchEnforce(interfaceRequests)
|
||||
}
|
||||
|
||||
32
util/json.go
32
util/json.go
@@ -67,3 +67,35 @@ func TryJsonToAnonymousStruct(j string) (interface{}, error) {
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// InterfaceToEnforceValue converts a single request value for use in Casbin ABAC enforcement.
|
||||
// - Strings that are valid JSON objects are converted to anonymous structs so Casbin can
|
||||
// access their fields (e.g. r.sub.DivisionGuid).
|
||||
// - Maps (map[string]interface{}) produced by direct JSON unmarshaling are re-marshaled and
|
||||
// then converted to anonymous structs in the same way.
|
||||
// - All other values are returned unchanged.
|
||||
func InterfaceToEnforceValue(v interface{}) interface{} {
|
||||
switch val := v.(type) {
|
||||
case string:
|
||||
jStruct, err := TryJsonToAnonymousStruct(val)
|
||||
if err == nil {
|
||||
return jStruct
|
||||
}
|
||||
return val
|
||||
case map[string]interface{}:
|
||||
// The value was already decoded as a JSON object; re-encode it so we
|
||||
// can reuse TryJsonToAnonymousStruct to produce a named-field struct
|
||||
// that Casbin can evaluate with dot-notation (r.sub.Field).
|
||||
jsonBytes, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
return val
|
||||
}
|
||||
jStruct, err := TryJsonToAnonymousStruct(string(jsonBytes))
|
||||
if err == nil {
|
||||
return jStruct
|
||||
}
|
||||
return val
|
||||
default:
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,3 +381,25 @@ func StringToInterfaceArray2d(arrays [][]string) [][]interface{} {
|
||||
}
|
||||
return interfaceArrays
|
||||
}
|
||||
|
||||
// InterfaceToEnforceArray converts a []interface{} request for use in Casbin ABAC enforcement.
|
||||
// Each element is processed by InterfaceToEnforceValue: plain strings that are valid JSON
|
||||
// objects and map values decoded directly from JSON are both converted to anonymous structs
|
||||
// so Casbin can evaluate attribute-based rules with dot-notation (r.sub.Field).
|
||||
func InterfaceToEnforceArray(array []interface{}) []interface{} {
|
||||
result := make([]interface{}, len(array))
|
||||
for i, elem := range array {
|
||||
result[i] = InterfaceToEnforceValue(elem)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// InterfaceToEnforceArray2d applies InterfaceToEnforceArray to every row in a
|
||||
// two-dimensional slice, for use with Casbin BatchEnforce.
|
||||
func InterfaceToEnforceArray2d(arrays [][]interface{}) [][]interface{} {
|
||||
result := make([][]interface{}, len(arrays))
|
||||
for i, arr := range arrays {
|
||||
result[i] = InterfaceToEnforceArray(arr)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user