golang - 优雅的方式来省略json属性被序列化

时间:2017-09-26 13:20:10

标签: json go

我有一个用户结构,它有敏感字段,如密码:

type User struct {
    UID string `json:"uid"  binding:"required"`
    Password string `json:"password" binding:"required"`
    EmailAddress string `json:"email" binding:"required"`
}

现在我希望能够使用此结构来注册用户并更新,删除以及查看。我不想要的是密码被序列化以供查看。当然,我可以制作一个定制的编组,但这是唯一的方法吗?我尝试使用json:"-"选项,但这也导致它在解组时被忽略,这是我不想要的。还有更好的方法吗?

修改 当然,为了让你们中的一些人放心,我不打算用明文存储密码。这是密码的bcrypt哈希,但仍然如此。我不希望在搜索用户时返回它。

5 个答案:

答案 0 :(得分:4)

我说如果你想要自定义封送,实现json.Marshaler是一个优雅的解决方案。在这种情况下,它非常简单:

func (u User) MarshalJSON() ([]byte, error) {
    type user User // prevent recursion
    x := user(u)
    x.Password = ""
    return json.Marshal(x)
}

添加" omitempty"在您的用户类型中,如果您在编组时根本不想要密码字段。

答案 1 :(得分:3)

一个简单的解决方案是在编组之前清理用户结构:

type User struct {
    UID          string `json:"uid"  binding:"required"`
    Password     string `json:"password,omitempty" binding:"required"`
    EmailAddress string `json:"email" binding:"required"`
}

func sanitizeUser(u User) User {
    return User{u.UID, "", u.EmailAddress}
}

演示:https://play.golang.org/p/RjKVoFc9o8

答案 2 :(得分:3)

我会选择其他结构和组合。

密码不应该以纯文本形式存储,应该安全地进行哈希处理(bcrypt,pbkdf2等)。该哈希值是必须存储的哈希值,永远不应该被序列化。通过使用合成,您可以执行以下操作:

type User struct {
    UID string `json:"uid"  binding:"required"`
    HashedPassword string `json:"-"`
    EmailAddress string `json:"email" binding:"required"`
}

type UserFormData struct {
   User
   Password string `json:"password" binding:"required"`
}

这也为您提供了更大的灵活性。例如,如果您要求用户确认密码,您只需更改UserFormData结构,如下所示:

type UserFormData struct {
   User
   Password string `json:"password" binding:"required"`
   ConfirmPassword string `json:"confirm_password" binding:"required"`
}

将序列化详细信息保留在User对象之外也具有优势。

答案 3 :(得分:1)

  

现在我希望能够使用此结构来注册用户并更新,删除以及查看。

另一个解决方案是不在结构中存储密码。您不需要它来查看,删除或更新(通常)。

您需要它来创建用户记录,此时您将在数据存储中存储哈希。

您需要它来验证其身份(登录时),此时您将验证数据存储中的哈希,然后通常会发出一个可用于继续访问服务的令牌。

因此,您只需要几点,并且在这些点上您可以简单地将其保存在内存中并验证身份,对于大多数操作,它不需要在结构中公开或存储。这比IMO在结构中更优雅,它可以很容易地在导出或日志记录中被错误地暴露。

答案 4 :(得分:0)

您可以使用select语句查询数据库,以仅获取所需的字段。

db.Model(&User{}).Select([]string{"uid","email"}).Find(&users)

还要在您的用户类型中添加omitempty,因为对于选择中不包括的字段会发送空响应。