dpjr86761 2017-03-15 18:41
浏览 107
已采纳

根据用户角色控制字段的可见性

I'd like to hide/show some fields of a model depending on User role.

What would be the most idiomatic way to implement it?

I don't really want to create N different types of the same model (where N is amount of User roles). Like: UserEmployee, AdminEmployee, WhateverEmployee.

It would be perfect if there is some solution that uses the tags for it:

type Employee struct {
   ID string `visibility:"admin,user"`
   Name string `visibility:"admin,user"`
   Salary int `visibility:"admin"`
}

jsonBytes, _ := someLib.Marshal(Employee{"1", "John", 5000}, "user")

fmt.Println(string(jsonBytes)) // {"id":"1","name":"John"}

The question is really pretty broad. I just wanted to know how you handle this situation or what is the most common way to do it in the Go community. I want clean and centralized (same for all models) solution that won't require to produce tons of duplicated code.

What have I tried before: I've just tried to use separate models for all cases and cast between them.

  • 写回答

2条回答 默认 最新

  • dphphvs496524 2017-03-17 06:39
    关注
    1. Create an empty struct of your type (Employee in this problem) that will hold the filtered data.
    2. Use the reflect package to compare if the field tag contains the desired tag value (visibility role).
    3. Copy values of base struct to our filter struct when we find a tag match and json marshal the output struct:

    package main
    
    import (
        "encoding/json"
        "fmt"
        "reflect"
        "strings"
    )
    
    type Employee struct {
        ID       string          `visibility:"admin, hr, user" json:"id,omitempty"`
        Name     string          `visibility:"admin, hr, user" json:"name,omitempty"`
        Salary   int             `visibility:"admin, hr" json:"salary,omitempty"`
        Password string          `visibility:"admin" json:"password,omitempty"`
        Rights   map[string]bool `visibility:"admin" json:"rights,omitempty"`
        Boss     *Employee       `visibility:"admin, hr" json:"boss,omitempty"`
    }
    
    func filterEmployee(emp Employee, role string) Employee {
        var fEmployee Employee
        ev := reflect.ValueOf(emp)
        et := reflect.TypeOf(emp)
    
        // Iterate through each field within the struct
        for i := 0; i < ev.NumField(); i++ {
            v := ev.Field(i)
            t := et.Field(i)
            roles := t.Tag.Get("visibility")
    
            if strings.Contains(roles, role) {
                switch i {
                case 0: // ID
                    fEmployee.ID = v.String()
                case 1: // Name
                    fEmployee.Name = v.String()
                case 2: // Salary
                    fEmployee.Salary = int(v.Int())
                case 3: // Password
                    fEmployee.Password = v.String()
                case 4: // Rights
                    fEmployee.Rights = v.Interface().(map[string]bool)
                case 5: // Boss
                    fEmployee.Boss = v.Interface().(*Employee)
                }
            }
        }
        return fEmployee
    }
    
    func main() {
    
        e := Employee{
            "1",
            "Jack",
            100000,
            "password321",
            map[string]bool{"create": false, "update": false},
            &Employee{
                "2",
                "John",
                120000,
                "pwd",
                map[string]bool{"create": true, "update": true},
                nil,
            },
        }
    
        fuser := filterEmployee(e, "user")
        fhr := filterEmployee(e, "hr")
        fadmin := filterEmployee(e, "admin")
    
        buser, err := json.MarshalIndent(fuser, "", "  ")
        if err != nil {
            fmt.Println(err)
        }
        fmt.Println("Filtering with role user: ")
        fmt.Println(string(buser))
    
        bhr, err := json.MarshalIndent(fhr, "", "  ")
        if err != nil {
            fmt.Println(err)
        }
        fmt.Println("
    Filtering with role hr: ")
        fmt.Println(string(bhr))
    
        badmin, err := json.MarshalIndent(fadmin, "", "  ")
        if err != nil {
            fmt.Println(err)
        }
        fmt.Println("
    Filtering with role admin: ")
        fmt.Println(string(badmin))
    }
    

    Output:

    Filtering with role user: 
    {
      "id": "1",
      "name": "Jack"
    }
    
    Filtering with role hr: 
    {
      "id": "1",
      "name": "Jack",
      "salary": 100000,
      "boss": {
        "id": "2",
        "name": "John",
        "salary": 120000,
        "password": "pwd",
        "rights": {
          "create": true,
          "update": true
        }
      }
    }
    
    Filtering with role admin: 
    {
      "id": "1",
      "name": "Jack",
      "salary": 100000,
      "password": "password321",
      "rights": {
        "create": false,
        "update": false
      },
      "boss": {
        "id": "2",
        "name": "John",
        "salary": 120000,
        "password": "pwd",
        "rights": {
          "create": true,
          "update": true
        }
      }
    }
    

    Playground

    EDIT: Updated answer for asker's request.

    View the old playground for previous answer that ran into issues.

    Old Playground

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 专家修改了标签 5月16日

悬赏问题

  • ¥15 2020长安杯与连接网探
  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么
  • ¥15 banner广告展示设置多少时间不怎么会消耗用户价值
  • ¥16 mybatis的代理对象无法通过@Autowired装填
  • ¥15 可见光定位matlab仿真
  • ¥15 arduino 四自由度机械臂
  • ¥15 wordpress 产品图片 GIF 没法显示
  • ¥15 求三国群英传pl国战时间的修改方法
  • ¥15 matlab代码代写,需写出详细代码,代价私
  • ¥15 ROS系统搭建请教(跨境电商用途)