openapi.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. package middleware
  2. import (
  3. "crypto/hmac"
  4. "crypto/sha256"
  5. "encoding/hex"
  6. "errors"
  7. "github.com/gin-gonic/gin"
  8. "gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
  9. "net/http"
  10. "strconv"
  11. "time"
  12. )
  13. const apiKeyHeader = "X-API-KEY"
  14. const apiSignatureHeader = "X-API-SIGNATURE"
  15. const apiTimestampHeader = "X-API-TIMESTAMP"
  16. // 这些 API Key 和 Secret 应该存储在安全的存储中,例如数据库或配置文件
  17. var validAPIKeys = map[string]string{
  18. "01HsBYiG": "A8CDJ1GQW4XNB3SZY7PKT92R6LQV8FW5",
  19. }
  20. // 验证签名是否有效
  21. func isValidSignature(apiKey, signature, timestamp string) bool {
  22. // 使用提供的 API Key 查找对应的 API Secret
  23. secret, ok := validAPIKeys[apiKey]
  24. if !ok {
  25. return false
  26. }
  27. // 计算签名,签名内容是 "apiKey + timestamp"
  28. message := apiKey + timestamp
  29. mac := hmac.New(sha256.New, []byte(secret))
  30. mac.Write([]byte(message))
  31. expectedSignature := hex.EncodeToString(mac.Sum(nil))
  32. // 验证客户端提供的签名是否与预期签名匹配
  33. return hmac.Equal([]byte(signature), []byte(expectedSignature))
  34. }
  35. // AuthCheckRole 权限检查中间件
  36. func ApiKeyAuthMiddleware() gin.HandlerFunc {
  37. return func(c *gin.Context) {
  38. apiKey := c.GetHeader(apiKeyHeader)
  39. signature := c.GetHeader(apiSignatureHeader)
  40. timestamp := c.GetHeader(apiTimestampHeader)
  41. // 检查 API Key, 签名和时间戳是否存在
  42. if apiKey == "" || signature == "" || timestamp == "" {
  43. err := errors.New("API Key, Signature, and Timestamp required")
  44. response.Error(c, http.StatusUnauthorized, err, err.Error())
  45. return
  46. }
  47. // 校验请求的签名是否有效
  48. if !isValidSignature(apiKey, signature, timestamp) {
  49. err := errors.New("Invalid Signature")
  50. response.Error(c, http.StatusForbidden, err, err.Error())
  51. return
  52. }
  53. // 校验时间戳是否在合理范围内(防止重放攻击)
  54. sec, _ := strconv.ParseInt(timestamp, 10, 64)
  55. reqTime := time.Unix(sec, 0)
  56. if time.Since(reqTime) > 5*time.Minute {
  57. err := errors.New("Request too old or invalid timestamp")
  58. response.Error(c, http.StatusForbidden, err, err.Error())
  59. return
  60. }
  61. // 如果鉴权成功,继续处理请求
  62. c.Next()
  63. return
  64. }
  65. }