草庐IT

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

coder 2023-07-02 原文

我想根据用户角色隐藏/显示模型的某些字段。

最惯用的实现方式是什么?

我真的不想创建同一模型的 N 个不同类型(其中 N 是用户角色的数量)。喜欢: UserEmployee、AdminEmployee、WhateverEmployee。

如果有一些使用标签的解决方案就完美了:

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"}

这个问题真的很广泛。我只是想知道您如何处理这种情况,或者在 Go 社区中最常见的处理方式是什么。我想要不需要产生大量重复代码的干净和集中(所有型号都相同)的解决方案。

我之前尝试过什么:我只是尝试对所有情况使用单独的模型并在它们之间进行转换。

最佳答案

  1. 创建一个您的类型(本问题中的 Employee)的空结构,用于保存过滤后的数据。
  2. 使用reflect要比较的包是否字段标签包含所需的标签值(可见性角色)。
  3. 当我们找到标签匹配和 json marshal 时,将基本结构的值复制到我们的过滤器结构中输出结构:

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("\nFiltering with role hr: ")
    fmt.Println(string(bhr))

    badmin, err := json.MarshalIndent(fadmin, "", "  ")
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println("\nFiltering with role admin: ")
    fmt.Println(string(badmin))
}

输出:

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

编辑:针对提问者的请求更新了答案。

查看旧的 playground 以获取以前遇到问题的答案。

Old Playground

关于json - 根据用户角色控制字段可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42818156/

有关json - 根据用户角色控制字段可见性的更多相关文章

  1. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  2. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  3. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  4. Ruby Readline 在向上箭头上使控制台崩溃 - 2

    当我在Rails控制台中按向上或向左箭头时,出现此错误:irb(main):001:0>/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/rb-readline-0.4.2/lib/rbreadline.rb:4269:in`blockin_rl_dispatch_subseq':invalidbytesequenceinUTF-8(ArgumentError)我使用rvm来管理我的ruby​​安装。我正在使用=>ruby-2.0.0-p247[x86_64]我使用bundle来管理我的gem,并且我有rb-readline(0.4.2)(人们推荐的最少

  5. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  6. ruby-on-rails - 带 Spring 锁的 Rails 4 控制台 - 2

    我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.

  7. ruby-on-rails - openshift 上的 rails 控制台 - 2

    我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新ruby​​gems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems

  8. ruby - 即时确定方法的可见性 - 2

    我正在编写一个方法,它将在一个类中定义一个实例方法;类似于attr_accessor:classFoocustom_method(:foo)end我通过将custom_method函数添加到Module模块并使用define_method定义方法来实现它,效果很好。但我无法弄清楚如何考虑类(class)的可见性属性。例如,在下面的类中classFoocustom_method(:foo)privatecustom_method(:bar)end第一个生成的方法(foo)必须是公共(public)的,第二个(bar)必须是私有(private)的。我怎么做?或者,如何找到调用我的cust

  9. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  10. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

随机推荐