Json 仅取消编组已批准的字段

Json 仅取消编组已批准的字段,json,go,reflection,unmarshalling,Json,Go,Reflection,Unmarshalling,我试图授予用户编辑结构的某些字段的权限。 此字段将根据操作、上下文和当前用户的角色而有所不同 目前,我正在以一种势在必行的方式来做这件事,但它相当乏味,而且不可扩展 我认为拥有一个已批准的\u字段列表可能是一个不错的、更具可扩展性的解决方案,但我不知道如何完成这一点。我认为反思是一条路,但我知道的还不够 任何灵感都会有所帮助 type Foo struct { Bar1 int Bar2 int Bar3 int } foo := Foo{} approved_fields :=

我试图授予用户编辑结构的某些字段的权限。 此字段将根据操作、上下文和当前用户的角色而有所不同

目前,我正在以一种势在必行的方式来做这件事,但它相当乏味,而且不可扩展

我认为拥有一个
已批准的\u字段列表
可能是一个不错的、更具可扩展性的解决方案,但我不知道如何完成这一点。我认为反思是一条路,但我知道的还不够

任何灵感都会有所帮助

type Foo struct {
  Bar1 int
  Bar2 int
  Bar3 int
}

foo := Foo{}
approved_fields := []string{"Bar1", "Bar2"}
decode(json_data, &foo, approved_fields)

foo2 := Foo{}
approved_fields := []string{"Bar1", "Bar3"}
decode(json_data, &foo2, approved_fields)

下面是我如何考虑解决这个问题的。可能有更有效的方法,因为我在选择性地选择字段之前对整个项目进行解组

import (
    "encoding/json"
    "log"
    "reflect"

    "github.com/pkg/errors"
)

func fieldByName(s string, v interface{}) (reflect.Value, error) {
    el := reflect.ValueOf(v).Elem()
    fbn := el.FieldByName(s)
    if !fbn.IsValid() {
        return fbn, errors.Errorf("does not have field named %s", s)
    }
    return fbn, nil
}

func decode(data []byte, v interface{}, approvedFields []string) error {
    typeOf := reflect.TypeOf(v)
    if typeOf.Kind() == reflect.Ptr {
        typeOf = typeOf.Elem()
    }
    if typeOf.Kind() == reflect.Slice {
        return errors.New("does not support slices")
    }

    newItem := reflect.New(typeOf)
    newItemInterface := newItem.Interface()
    if err := json.Unmarshal(data, &newItemInterface); err != nil {
        return errors.Wrap(err, "json unmarshall")
    }
    for _, approvedField := range approvedFields {
        fbn, err := fieldByName(approvedField, v)
        if err != nil {
            return errors.Wrap(err, "field by name")
        }
        val, _ := fieldByName(approvedField, newItemInterface)
        fbn.Set(val)
    }
    return nil
}
测试:

func TestBar1Bar2(t *testing.T) {
    var json_data []byte
    {
        f := &Foo{
            Bar1: 1,
            Bar2: 2,
            Bar3: 3,
        }
        json_data, _ = json.Marshal(f)
    }
    approved_fields := []string{"Bar1", "Bar2"}
    f := &Foo{}
    err := decode(json_data, f, approved_fields)
    if err != nil {
        t.Fatal(err)
    }
    assert.Equal(t, f.Bar1, 1)
    assert.Equal(t, f.Bar2, 2)
    assert.Equal(t, f.Bar3, 0)
}

下面是我如何考虑解决这个问题的。可能有更有效的方法,因为我在选择性地选择字段之前对整个项目进行解组

import (
    "encoding/json"
    "log"
    "reflect"

    "github.com/pkg/errors"
)

func fieldByName(s string, v interface{}) (reflect.Value, error) {
    el := reflect.ValueOf(v).Elem()
    fbn := el.FieldByName(s)
    if !fbn.IsValid() {
        return fbn, errors.Errorf("does not have field named %s", s)
    }
    return fbn, nil
}

func decode(data []byte, v interface{}, approvedFields []string) error {
    typeOf := reflect.TypeOf(v)
    if typeOf.Kind() == reflect.Ptr {
        typeOf = typeOf.Elem()
    }
    if typeOf.Kind() == reflect.Slice {
        return errors.New("does not support slices")
    }

    newItem := reflect.New(typeOf)
    newItemInterface := newItem.Interface()
    if err := json.Unmarshal(data, &newItemInterface); err != nil {
        return errors.Wrap(err, "json unmarshall")
    }
    for _, approvedField := range approvedFields {
        fbn, err := fieldByName(approvedField, v)
        if err != nil {
            return errors.Wrap(err, "field by name")
        }
        val, _ := fieldByName(approvedField, newItemInterface)
        fbn.Set(val)
    }
    return nil
}
测试:

func TestBar1Bar2(t *testing.T) {
    var json_data []byte
    {
        f := &Foo{
            Bar1: 1,
            Bar2: 2,
            Bar3: 3,
        }
        json_data, _ = json.Marshal(f)
    }
    approved_fields := []string{"Bar1", "Bar2"}
    f := &Foo{}
    err := decode(json_data, f, approved_fields)
    if err != nil {
        t.Fatal(err)
    }
    assert.Equal(t, f.Bar1, 1)
    assert.Equal(t, f.Bar2, 2)
    assert.Equal(t, f.Bar3, 0)
}

谢谢,我认为这很有帮助,我也在研究一种策略,在这种策略中,我只使用允许的参数声明一个中间类型,然后进行深度复制。这将有助于切片和嵌套结构。您认为呢?“声明一个只允许参数的中间类型”您必须在编译之前声明所需类型的每个变体。正确的?我的解决方案可以修改为使用切片非常容易。嵌套结构也应该是可能的。这只是如何构造已批准字段的语法的问题。e、 g
“Bar1.Field1”
访问嵌套结构的字段。我会这样做,这样你就可以将你的approved_字段从应用程序中分离出来(将它们放入具有用户组和权限的数据库中)。谢谢你,我认为这很有帮助,我还在研究一种策略,在这种策略中,我声明一个只允许参数的中间类型,然后进行深度复制。这将有助于切片和嵌套结构。您认为呢?“声明一个只允许参数的中间类型”您必须在编译之前声明所需类型的每个变体。正确的?我的解决方案可以修改为使用切片非常容易。嵌套结构也应该是可能的。这只是如何构造已批准字段的语法的问题。e、 g
“Bar1.Field1”
访问嵌套结构的字段。我会这样做,这样你就可以将你的approved_字段从应用程序中分离出来(将它们放入具有用户组和权限的数据库中)