feat: 中间件-接口加解密AES-CBC

This commit is contained in:
TsMask
2024-08-14 10:42:13 +08:00
parent e7092ad058
commit 1b1c15995d
2 changed files with 141 additions and 2 deletions

View File

@@ -8,8 +8,13 @@ const (
// 响应-msg错误失败
MSG_ERROR = "error"
// 响应-msg正常成功
CODE_SUCCESS = 1
// 响应-code正常成功
CODE_SUCCESS = 1
// 响应-msg正常成功
MSG_SUCCESS = "success"
// 响应-code加密数据
CODE_ENCRYPT = 2
// 响应-msg加密数据
MSG_ENCRYPT = "encrypt"
)

View File

@@ -0,0 +1,134 @@
package middleware
import (
"bytes"
"encoding/json"
"fmt"
"io"
"be.ems/src/framework/config"
constResult "be.ems/src/framework/constants/result"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/crypto"
"be.ems/src/framework/utils/parse"
"github.com/gin-gonic/gin"
)
// CryptoApi 接口加解密
//
// 示例参数middleware.CryptoApi(true, true)
//
// 参数表示:对请求解密,对响应加密
//
// 请将中间件放在最前置,对请求优先处理
func CryptoApi(requestDecrypt, responseEncrypt bool) gin.HandlerFunc {
return func(c *gin.Context) {
// 请求解密时对请求data注入
if requestDecrypt {
contentDe := ""
if c.Request.Method == "GET" {
contentDe = c.Query("data")
} else if c.ContentType() == gin.MIMEJSON {
var body struct {
Data string `json:"data" binding:"required"`
}
if err := c.ShouldBindJSON(&body); err == nil {
contentDe = body.Data
}
}
// 是否存在data字段数据
if contentDe == "" {
c.JSON(400, map[string]any{
"code": constResult.CODE_ERROR,
"msg": "decrypt not found field data",
})
c.Abort() // 停止执行后续的处理函数
return
}
// 解密
apiKey := config.Get("aes.apiKey").(string)
dataBodyStr, err := crypto.AESDecryptBase64(contentDe, apiKey)
if err != nil {
logger.Errorf("CryptoApi decrypt err => %v", err)
c.JSON(400, map[string]any{
"code": constResult.CODE_ERROR,
"msg": "decrypted data could not be parsed",
})
c.Abort() // 停止执行后续的处理函数
return
}
// 分配回请求体
c.Request.Body = io.NopCloser(bytes.NewBuffer([]byte(dataBodyStr)))
}
// 响应加密时替换原有的响应体
var rbw *replaceBodyWriter
if responseEncrypt {
rbw = &replaceBodyWriter{
body: &bytes.Buffer{},
ResponseWriter: c.Writer,
}
c.Writer = rbw
}
// 调用下一个处理程序
c.Next()
// 响应加密时对响应data数据进行加密
if responseEncrypt {
// 满足成功并带数据的响应进行加密
if c.Writer.Status() == 200 {
var resBody map[string]any
json.Unmarshal(rbw.body.Bytes(), &resBody)
codeV, codeOk := resBody["code"]
dataV, dataOk := resBody["data"]
if codeOk && dataOk {
if parse.Number(codeV) == constResult.CODE_SUCCESS {
byteBodyData, _ := json.Marshal(dataV)
// 加密
apiKey := config.Get("aes.apiKey").(string)
contentEn, err := crypto.AESEncryptBase64(string(byteBodyData), apiKey)
if err != nil {
logger.Errorf("CryptoApi encrypt err => %v", err)
rbw.ReplaceWrite([]byte(fmt.Sprintf(`{"code":"%d","msg":"encrypt err"}`, constResult.CODE_ERROR)))
} else {
// 响应加密
byteBody, _ := json.Marshal(map[string]any{
"code": constResult.CODE_ENCRYPT,
"msg": constResult.MSG_ENCRYPT,
"data": contentEn,
})
rbw.ReplaceWrite(byteBody)
}
}
} else {
rbw.ReplaceWrite(nil)
}
} else {
rbw.ReplaceWrite(nil)
}
}
//
}
}
// replaceBodyWriter 替换默认的响应体
type replaceBodyWriter struct {
gin.ResponseWriter
body *bytes.Buffer
}
// Write 写入响应体
func (r replaceBodyWriter) Write(b []byte) (int, error) {
return r.body.Write(b)
}
// ReplaceWrite 替换响应体
func (r *replaceBodyWriter) ReplaceWrite(b []byte) (int, error) {
if b == nil {
return r.ResponseWriter.Write(r.body.Bytes())
}
r.body = &bytes.Buffer{}
r.body.Write(b)
return r.ResponseWriter.Write(r.body.Bytes())
}