2017-09-26 62 views
2

省略JSON属性我有一个用户结构,它具有像密码敏感字段:golang - 优雅的方式被序列化

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

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

编辑: 为了让你们中的一些人放心,我当然不会以明文存储密码。这是密码的bcrypt散列,但仍然如此。我不希望它在我搜索用户时返回。

+4

或者你可以使用2个结构体,一个带有“公共”信息和另一个嵌入公共的“完整”版本,并添加诸如密码之类的“私人”信息。在查看时,只发送/序列化嵌入式公共结构。例如,请参阅相关问题:[使用另一个结构赋值结构](https://stackoverflow.com/questions/31981592/assign-struct-with-another-struct/31981736#31981736)。 – icza

+2

哦,这可能是最接近你的“优雅”,尤其是现在你可以用不同的标签来转换相同的结构。我仍然会在“自定义编组器”下标记它,但它比“JSONMarshaler”实现更简单。 – JimB

回答

3

我想说实施json.Marshaler是,如果你想自定义编组的优雅的解决方案。这是在这种情况下很简单:

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

添加“omitempty”在你的用户类型,如果你不想要的密码字段编组时,在所有。

+0

我想你是对的。没有任何进展。我尝试了不同的方式,但在优雅方面,只有这一点。 – ystark

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

1

现在我想能够使用这个结构来注册一个用户和更新,删除,但也可以查看。

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

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

您需要它来验证他们的身份(登录时),在此时您可以验证数据存储中的哈希值,然后通常会发出令牌,以便他们继续访问该服务。

所以只有几点你需要它,在这些点你可以简单地将它保存在内存中并验证身份,它不需要暴露或存储在结构中以用于大多数操作。这比国际海事组织更优雅,因为它在结构中可以非常容易地在导出或日志记录中出错。

+1

这是一个很好的观点。要解析json文档中的密码,您可以简单地解组两次。一旦进入你的用户结构(它没有密码字段),然后再进入另一个只有密码字段的结构。如果这是有道理的。 – Peter

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

其中也有优势,让您的用户对象之外的序列化的详细信息。