将Go语言结构体中的字符串进行转换。

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

transforming strings in a golang struct

问题

我有一个AES加密的JSON文件。结构如下:

{
    "username": "asdf123ASLdf3",
    "password": "elisjdvo4etQW"
}

还有一个用于保存这些值的结构体:

type Secrets struct {
    Username string `json:"username"`
    Password string `json:"password"`
}

将加密的JSON值加载到结构体中很容易,但我真正想要的是一个包含未加密值的结构体。

因此,对于每个值,我想要运行一个函数:

aesDecrypt(key string, value string) string

我可以在第一次加载时完成这个操作,或者将所有内容移动到一个新的结构体中。

我希望避免重复使用JSON键或字段名。

怎样才能做到最好呢?

(也欢迎其他在Go中管理加密密钥的方法)

英文:

I've got a json file of AES encrypted secrets. The structure is:

{
    "username": "asdf123ASLdf3",
    "password": "elisjdvo4etQW"
}

And a struct to hold these values

type Secrets struct {
    Username string `json:"username"`
    Password string `json:"password"`
}

It's easy to load the encrypted json values into the struct, but what I really want is a struct with the unencrypted values.

So, for each value, I'd like to run it though a function:

aesDecrypt(key string, value string) string

I'm happy to have this done on the first load, or to move everything over into a new struct.

I would like to avoid repeating the json keys or the field names.

What's the best way to do this?

(Also open to other ways to manage encrypted secrets in Go)

答案1

得分: 2

一种选择是定义一个自定义的JSON解析器。另一种选择是,正如你提到的,将其复制到另一个结构体中。

  1. 实现Unmarshaler接口

关键的洞察力是知道你可以通过实现Unmarshaler接口来覆盖json.Unmarshal的行为。在我们的情况下,这意味着定义一个函数func (ss *Secrets) UnmarshalJSON(bb []byte) error,当你尝试将任何JSON解析为Secrets时,它将执行AES解密。

package main

import "fmt"
import "encoding/json"

type Secrets struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

func main() {
	jj := []byte(`{
		"username": "asdf123ASLdf3",
		"password": "elisjdvo4etQW"
	}`)
	var ss Secrets
	json.Unmarshal(jj, &ss)
	fmt.Println(ss)
}

func aesDecrypt(key, value string) string {
	return fmt.Sprintf("'%s' decrypted with key '%s'", value, key)
}

func (ss *Secrets) UnmarshalJSON(bb []byte) error {
	var objmap map[string]*string
	err := json.Unmarshal(bb, &objmap)
	ss.Username = aesDecrypt("my key", *objmap["password"])
	ss.Password = aesDecrypt("my key", *objmap["username"])
	return err
}

这将输出一个Secrets结构体:

{'elisjdvo4etQW' decrypted with key 'my key'
 'asdf123ASLdf3' decrypted with key 'my key'}

在Go Playground上查看示例。

  1. 复制到另一个结构体

每次需要解密JSON时,你可以简单地创建一个新的Secrets结构体。如果你经常这样做,或者不需要中间状态,这可能会很繁琐。

package main

import "fmt"
import "encoding/json"

type Secrets struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

func main() {
	jj := []byte(`{
		"username": "asdf123ASLdf3",
		"password": "elisjdvo4etQW"
	}`)
	var ss Secrets
	json.Unmarshal(jj, &ss)
	decoded := Secrets{
		aesDecrypt(ss.Username, "my key"),
		aesDecrypt(ss.Password, "my key")}
	fmt.Println(decoded)
}

func aesDecrypt(key, value string) string {
	return fmt.Sprintf("'%s' decrypted with key '%s'", value, key)
}

在Go Playground上查看示例。

这与上面的输出相同:

{'elisjdvo4etQW' decrypted with key 'my key'
 'asdf123ASLdf3' decrypted with key 'my key'}

显然,你应该使用不同版本的aesDecrypt,我的只是一个虚拟的。并且,像往常一样,你应该在自己的代码中实际检查返回的错误。

英文:

One option is to define a custom JSON Unmarshaler. Another is, as you mention, copy it to another struct.

  1. Implementing the Unmarshaler interface

    The key insight is knowing that you can override json.Unmarshal's
    behaviour by implementing the Unmarshaler interface. In our
    case, that means defining a function func (ss *Secrets)
    UnmarshalJSON(bb []byte) error
    that will do the AES Decryption when
    you try to unmarshal any JSON to a Secrets.

    package main
    
    import "fmt"
    import "encoding/json"
    
    type Secrets struct {
    	Username string `json:"username"`
    	Password string `json:"password"`
    }
    
    func main() {
    	jj := []byte(`{
    		"username": "asdf123ASLdf3",
    		"password": "elisjdvo4etQW"
    	}`)
    	var ss Secrets
    	json.Unmarshal(jj, &ss)
    	fmt.Println(ss)
    }
    
    func aesDecrypt(key, value string) string {
    	return fmt.Sprintf("'%s' decrypted with key '%s'", value, key)
    }
    
    func (ss *Secrets) UnmarshalJSON(bb []byte) error {
    	var objmap map[string]*string
    	err := json.Unmarshal(bb, &objmap)
    	ss.Username = aesDecrypt("my key", *objmap["password"])
    	ss.Password = aesDecrypt("my key", *objmap["username"])
    	return err
    }
    

    This outputs a Secrets struct:

    {'elisjdvo4etQW' decrypted with key 'my key'
     'asdf123ASLdf3' decrypted with key 'my key'}
    

    See it in action at the Go Playground.

  2. Copying to another struct

    You could simply make a new Secrets struct every time you need to
    decrypt the JSON. This could be tedious if you do it alot, or if you
    have no need for the intermediate state.

    package main
    
    import "fmt"
    import "encoding/json"
    
    type Secrets struct {
    	Username string `json:"username"`
    	Password string `json:"password"`
    }
    
    func main() {
    	jj := []byte(`{
    		"username": "asdf123ASLdf3",
    		"password": "elisjdvo4etQW"
    	}`)
    	var ss Secrets
    	json.Unmarshal(jj, &ss)
    	decoded := Secrets{
            aesDecrypt(ss.Username, "my key"),
            aesDecrypt(ss.Password, "my key")}
    	fmt.Println(decoded)
    }
    
    func aesDecrypt(key, value string) string {
    	return fmt.Sprintf("'%s' decrypted with key '%s'", value, key)
    }
    

    Check it out at Go Playground.

    This has the same output as above:

    {'elisjdvo4etQW' decrypted with key 'my key'
     'asdf123ASLdf3' decrypted with key 'my key'}
    

Obviously, you would use a different version of aesDecrypt, mine's
just a dummy. And, as always, you should actually be checking the
returned errors in your own code.

huangapple
  • 本文由 发表于 2015年6月18日 23:19:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/30919448.html
匿名

发表评论

匿名网友

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

确定