将子结构体转换为字符串并再次转换为子结构体。

huangapple go评论75阅读模式
英文:

Convert sub struct to string and back

问题

我遇到了一些问题,涉及到UnmarshalJSONMarshalJSON方法,我不确定我是否正确理解了它们,或者至少我没有找到错误的地方。在我搜索了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:&quot;primaryKey,type:string,size:36,&lt;-:create&quot; json:&quot;id&quot;`
	Username  string               `gorm:&quot;unique&quot; json:&quot;username&quot;`
	Password  PasswordHash         `gorm:&quot;type:string&quot; json:&quot;password&quot;`
	CreatedAt time.Time            `gorm:&quot;autoCreateTime:milli&quot; json:&quot;created_at&quot;`
	UpdatedAt time.Time            `gorm:&quot;autoUpdateTime:milli&quot; json:&quot;updated_at,omitempty&quot;`
	DeletedAt gorm.DeletedAt       `gorm:&quot;index&quot; json:&quot;deleted_at,omitempty&quot;`
}

which when i try to convert into JSON, with the json.Marshal function from the build in encoding/json library, i get the following:

{&quot;id&quot;:&quot;3843298e-74d4-4dd7-8eff-007ab34a4c19&quot;,&quot;username&quot;:&quot;root&quot;,&quot;password&quot;:{},&quot;created_at&quot;:&quot;0001-01-01T00:00:00Z&quot;,&quot;updated_at&quot;:&quot;0001-01-01T00:00:00Z&quot;,&quot;deleted_at&quot;:null}

I expected some thing like:

{&quot;id&quot;:&quot;3843298e-74d4-4dd7-8eff-007ab34a4c19&quot;,&quot;username&quot;:&quot;root&quot;,&quot;password&quot;:&quot;$argon2id$v=19$m=4194304,t=1,p=64$Z9EFSTk26TQxx+Qv9g58gQ$4At0rvvv9trRcFZmSMXY0nISBuEt+1X8mCRAYbyXqSs&quot;,&quot;created_at&quot;:&quot;0001-01-01T00:00:00Z&quot;,&quot;updated_at&quot;:&quot;0001-01-01T00:00:00Z&quot;,&quot;deleted_at&quot;: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(
		&quot;$%s$v=%d$m=%d,t=%d,p=%d$%s$%s&quot;,
		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, &amp;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

huangapple
  • 本文由 发表于 2022年10月1日 03:51:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/73913421.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定