英文:
Convert sub struct to string and back
问题
我遇到了一些问题,涉及到UnmarshalJSON
和MarshalJSON
方法,我不确定我是否正确理解了它们,或者至少我没有找到错误的地方。在我搜索了3个小时后,仍然没有找到答案。
我有以下的User结构体:
type User struct {
ID uuid.UUID `gorm:"primaryKey,type:string,size:36,<-:create" json:"id"`
Username string `gorm:"unique" json:"username"`
Password PasswordHash `gorm:"type:string" json:"password"`
CreatedAt time.Time `gorm:"autoCreateTime:milli" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime:milli" json:"updated_at,omitempty"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at,omitempty"`
}
当我尝试使用内置的encoding/json
库中的json.Marshal
函数将其转换为JSON时,我得到了以下结果:
{"id":"3843298e-74d4-4dd7-8eff-007ab34a4c19","username":"root","password":{},"created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","deleted_at":null}
我期望得到如下结果:
{"id":"3843298e-74d4-4dd7-8eff-007ab34a4c19","username":"root","password":"$argon2id$v=19$m=4194304,t=1,p=64$Z9EFSTk26TQxx+Qv9g58gQ$4At0rvvv9trRcFZmSMXY0nISBuEt+1X8mCRAYbyXqSs","created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","deleted_at":null}
我似乎无法将password
字段转换为哈希密码的字符串。即使在PasswordHash
结构体上有以下方法:
type Params struct {
memory uint32
iterations uint32
parallelism uint8
saltLength uint32
keyLength uint32
}
type PasswordHash struct {
hash []byte
salt []byte
params Params
}
func (h *PasswordHash) String() string {
b64Salt := base64.RawStdEncoding.EncodeToString(h.salt)
b64Hash := base64.RawStdEncoding.EncodeToString(h.hash)
return fmt.Sprintf(
"$%s$v=%d$m=%d,t=%d,p=%d$%s$%s",
algoName,
argon2.Version,
h.params.memory,
h.params.iterations,
h.params.parallelism,
b64Salt,
b64Hash,
)
}
func (h *PasswordHash) UnmarshalJSON(data []byte) error {
var v string
if err := json.Unmarshal(data, &v); err != nil {
return err
}
params, salt, hash, err := decodeHash(v)
if err != nil {
return err
}
h.params = params
h.salt = salt
h.hash = hash
return nil
}
func (h *PasswordHash) MarshalJSON() ([]byte, error) {
//return []byte(h.String()), nil
return json.Marshal(h.String())
}
所以,我猜我的问题是,当尝试将用户转换为JSON时,MarshalJSON
方法不应该在PasswordHash结构体上调用吗?如果是这样,为什么我似乎无法得到一个字符串值?
英文:
I am having some trouble with the UnmarshalJSON
and MarshalJSON
i am not sure i understand them correctly or atleast i have an error that i have not been able to spot and in my 3 hours of googling i haven't been able find, so here goes.
I have the following User struct
type User struct {
ID uuid.UUID `gorm:"primaryKey,type:string,size:36,<-:create" json:"id"`
Username string `gorm:"unique" json:"username"`
Password PasswordHash `gorm:"type:string" json:"password"`
CreatedAt time.Time `gorm:"autoCreateTime:milli" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime:milli" json:"updated_at,omitempty"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at,omitempty"`
}
which when i try to convert into JSON, with the json.Marshal
function from the build in encoding/json
library, i get the following:
{"id":"3843298e-74d4-4dd7-8eff-007ab34a4c19","username":"root","password":{},"created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","deleted_at":null}
I expected some thing like:
{"id":"3843298e-74d4-4dd7-8eff-007ab34a4c19","username":"root","password":"$argon2id$v=19$m=4194304,t=1,p=64$Z9EFSTk26TQxx+Qv9g58gQ$4At0rvvv9trRcFZmSMXY0nISBuEt+1X8mCRAYbyXqSs","created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","deleted_at":null}
i can't seem to get the password
field to be a string of the hashed password.
even when i have the following methods on the PasswordHash
struct
type Params struct {
memory uint32
iterations uint32
parallelism uint8
saltLength uint32
keyLength uint32
}
type PasswordHash struct {
hash []byte
salt []byte
params Params
}
func (h *PasswordHash) String() string {
b64Salt := base64.RawStdEncoding.EncodeToString(h.salt)
b64Hash := base64.RawStdEncoding.EncodeToString(h.hash)
return fmt.Sprintf(
"$%s$v=%d$m=%d,t=%d,p=%d$%s$%s",
algoName,
argon2.Version,
h.params.memory,
h.params.iterations,
h.params.parallelism,
b64Salt,
b64Hash,
)
}
func (h *PasswordHash) UnmarshalJSON(data []byte) error {
var v string
if err := json.Unmarshal(data, &v); err != nil {
return err
}
params, salt, hash, err := decodeHash(v)
if err != nil {
return err
}
h.params = params
h.salt = salt
h.hash = hash
return nil
}
func (h *PasswordHash) MarshalJSON() ([]byte, error) {
//return []byte(h.String()), nil
return json.Marshal(h.String())
}
So i guess my question is, shouldn't the MarshalJSON
be called on the PasswordHash struct when trying to convert the user to JSON? and if so how come i can't seem to get it to be a string value?
答案1
得分: 1
你在MarshalJSON
中定义了一个接收者为*PasswordHash
的方法,但是你的值的类型是PasswordHash
。将接收者改为PasswordHash
,它就会按预期工作:https://go.dev/play/p/WukE_5JBEPL
英文:
You have MarshalJSON
defined with a receiver of *PasswordHash
, but your value is type PasswordHash
. Change the receiver to PasswordHash
and it works as expected: https://go.dev/play/p/WukE_5JBEPL
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论