一、原理
本篇为实现,可先阅读:保证api接口安全性的方式
二、实现
定义
const (
Newline = "\n"
Json = "application/json"
ContextType = "Content-type"
Nonce = "c-sign-nonce"
Version = "c-sign-version"
Timestamp = "c-sign-timestamp"
Authorization = "authorization"
)
type Auth struct {
Nonce string
Version string
Timestamp string
Authorization string
}
验证请求及签名是否合法(服务提供方使用)
func CheckHttpRequestAuth(auth *Auth, path string, body []byte, appKey string, appSecret string) bool {
h := md5.New()
h.Write(body)
b := h.Sum(nil)
base64Md5Str := base64.StdEncoding.EncodeToString(b)
// 1.timestamp验证 todo (防止恶意攻击)
// 2.nonce验证 todo
// 3.sign验证
sign := "c" + appKey + singature(auth.Timestamp, auth.Nonce, base64Md5Str, path, appSecret)
if sign == auth.Authorization {
return true
}
return false
}
获取鉴权header(请求方使用)
func GetRequestHeader(path string, body []byte, appKey string, appSecret string) map[string]string {
header := make(map[string]string, 0)
h := md5.New()
h.Write(body)
b := h.Sum(nil)
base64Md5Str := base64.StdEncoding.EncodeToString(b)
now := time.Now().UTC().Unix()
timeStr := strconv.FormatInt(now, 10)
nonce := _uuid.Rand().Hex()
header[ContextType] = Json
header[Nonce] = nonce
header[Version] = "1.0"
header[Timestamp] = timeStr
header[Authorization] = "c" + appKey + singature(timeStr, nonce, base64Md5Str, path, appSecret)
return header
}
签名方法(根据业务进行调整)
func singature(timeStr string, nonce string, md5Str string, path string, appSecret string) string {
b := bytes.Buffer{}
b.WriteString(Json)
b.WriteString(Newline)
b.WriteString(nonce)
b.WriteString(Newline)
b.WriteString(md5Str)
b.WriteString(Newline)
b.WriteString(timeStr)
b.WriteString(Newline)
b.WriteString(path)
mac := hmac.New(sha1.New, []byte(appSecret))
mac.Write([]byte(b.String()))
return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}
测试
const (
appKey = "EO8bvxGl"
appSecret = "215bc9d7e1ab16c663289d40cea8164b9b00e307"
)
func Test_GetRequestHeader(t *testing.T) {
path := "/api/v1/test"
body := []byte("{"a":"a", "b":1}")
headers := GetRequestHeader(path, body, appKey, appSecret)
for k, item := range headers {
// c-sign-timestamp: 1674119032
// c-sign-nonce: 0e30eb38-d63a-4f45-bace-b98d30f52040
// Authorization: cEO8bvxGlogcvH5eS4ABeFQAbKf08mMgZ1GE=
fmt.Println(k + ": ", item)
}
}
func TestCheckHttpRequestAuth(t *testing.T) {
auth := &Auth{
Nonce: "0e30eb38-d63a-4f45-bace-b98d30f52040",
Version: "1.0",
Timestamp: "1674119032",
Authorization: "cEO8bvxGlogcvH5eS4ABeFQAbKf08mMgZ1GE=",
}
path := "/api/v1/test"
body := []byte("{"a":"a", "b":1}")
got := CheckHttpRequestAuth(auth, path, body, appKey, appSecret)
fmt.Println("got:", got) // true
}