duanbo6482 2015-06-18 15:19
浏览 171
已采纳

在golang结构中转换字符串

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条回答 默认 最新

  • dpvomqeu396484 2015-06-18 15:59
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?