要给已有的系统启用加密解密,目前推荐的是aes的gcm模式的加密和解密,在微服务如果向前有公共方法处理 读取数据和写返回数据,那么比较简单,修改以前的公共方法,但是这样本地调试平时肯定是明文,所以要加判断,如果以前的读数据和写数据是五花八门那就比较麻烦,在微服务体系里面一般有网关这个服务,所以加密和解密就放在网关服务,大致如下:
常规的请求有GET,POST JSON, POST file,以及POST Form表单,返回一般是json 或者下载文件流,所以我们需要截获请求流和返回流,收到请求流解密数据 然后重新写入到请求流,收到返回流加密数据,重写返回流。
首先来看aes加密和解密程序aes.go
package aes
import (
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"crypto/rand"
"encoding/base64"
"encoding/hex"
"errors"
"io"
)
//加密字符串
func GcmEncrypt(key, plaintext string) (string, error) {
if len(key) != 32 && len(key) != 24 && len(key) != 16 {
return "", errors.New("the length of key is error")
}
if len(plaintext) < 1 {
return "", errors.New("plaintext is null")
}
keyByte := []byte(key)
plainByte:=[]byte(plaintext)
block, err := aes.NewCipher(keyByte)
if err != nil {
return "", err
}
aesGcm, err := cipher.NewGCM(block)
if err != nil {
return "", err
}
nonce := make([]byte, 12)
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return "", err
}
seal := aesGcm.Seal(nonce, nonce, plainByte, nil)
return base64.URLEncoding.EncodeToString(seal), nil
}
//解密字符串
func GcmDecrypt(key, cipherText string) (string, error) {
if len(key) != 32 && len(key) != 24 && len(key) != 16 {
return "", errors.New("the length of key is error")
}
if len(cipherText) < 1 {
return "", errors.New("cipherText is null")
}
cipherByte, err := base64.URLEncoding.DecodeString(cipherText)
if err != nil {
return "", err
}
if len(cipherByte) < 12 {
return "", errors.New("cipherByte is error")
}
nonce, cipherByte := cipherByte[:12], cipherByte[12:]
keyByte := []byte(key)
block, err := aes.NewCipher(keyByte)
if err != nil {
return "", err
}
aesGcm, err := cipher.NewGCM(block)
if err != nil {
return "", err
}
plainByte, err := aesGcm.Open(nil, nonce, cipherByte, nil)
if err != nil {
return "", err
}
return string(plainByte), nil
}
//生成32位md5字串
func GetAesKey(s string) string {
h := md5.New()
h.Write([]byte(s))
return hex.EncodeToString(h.Sum(nil))
}
再来看看网关转发程序proxy.go
package middleware
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/valyala/fasthttp"
"io/ioutil"
"runtime/debug"
"time"
)
var fastClient *fasthttp.Client
func init() {
fastClient = &fasthttp.Client{}
fastClient.MaxIdemponentCallAttempts = 1
fastClient.ReadTimeout = time.Second * 60
}
func GetHttpClient() *fasthttp.Client {
return fastClient
}
func GateWay() gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if e := recover(); e != nil {
stack := debug.Stack()
log("GateWay Recovery: err:%v, stack:%v", e, string(stack))
}
}()
err := Forward(c)
if err != nil {
response(c, 9999, "系统错误", err.Error())
}
return
}
}
func Forward(ctx *gin.Contex