secure_verification.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package middleware
  2. import (
  3. "net/http"
  4. "time"
  5. "github.com/gin-contrib/sessions"
  6. "github.com/gin-gonic/gin"
  7. )
  8. const (
  9. // SecureVerificationSessionKey 安全验证的 session key(与 controller 保持一致)
  10. SecureVerificationSessionKey = "secure_verified_at"
  11. secureVerificationMethodSessionKey = "secure_verified_method"
  12. // SecureVerificationTimeout 验证有效期(秒)
  13. SecureVerificationTimeout = 300 // 5分钟
  14. )
  15. // SecureVerificationRequired 安全验证中间件
  16. // 检查用户是否在有效时间内通过了安全验证
  17. // 如果未验证或验证已过期,返回 401 错误
  18. func SecureVerificationRequired() gin.HandlerFunc {
  19. return func(c *gin.Context) {
  20. // 检查用户是否已登录
  21. userId := c.GetInt("id")
  22. if userId == 0 {
  23. c.JSON(http.StatusUnauthorized, gin.H{
  24. "success": false,
  25. "message": "未登录",
  26. })
  27. c.Abort()
  28. return
  29. }
  30. // 检查 session 中的验证时间戳
  31. session := sessions.Default(c)
  32. verifiedAtRaw := session.Get(SecureVerificationSessionKey)
  33. if verifiedAtRaw == nil {
  34. c.JSON(http.StatusForbidden, gin.H{
  35. "success": false,
  36. "message": "需要安全验证",
  37. "code": "VERIFICATION_REQUIRED",
  38. })
  39. c.Abort()
  40. return
  41. }
  42. verifiedAt, ok := verifiedAtRaw.(int64)
  43. if !ok {
  44. // session 数据格式错误
  45. clearSecureVerificationSession(session)
  46. c.JSON(http.StatusForbidden, gin.H{
  47. "success": false,
  48. "message": "验证状态异常,请重新验证",
  49. "code": "VERIFICATION_INVALID",
  50. })
  51. c.Abort()
  52. return
  53. }
  54. // 检查验证是否过期
  55. elapsed := time.Now().Unix() - verifiedAt
  56. if elapsed >= SecureVerificationTimeout {
  57. // 验证已过期,清除 session
  58. clearSecureVerificationSession(session)
  59. c.JSON(http.StatusForbidden, gin.H{
  60. "success": false,
  61. "message": "验证已过期,请重新验证",
  62. "code": "VERIFICATION_EXPIRED",
  63. })
  64. c.Abort()
  65. return
  66. }
  67. c.Next()
  68. }
  69. }
  70. func clearSecureVerificationSession(session sessions.Session) {
  71. session.Delete(SecureVerificationSessionKey)
  72. session.Delete(secureVerificationMethodSessionKey)
  73. _ = session.Save()
  74. }
  75. // OptionalSecureVerification 可选的安全验证中间件
  76. // 如果用户已验证,则在 context 中设置标记,但不阻止请求继续
  77. // 用于某些需要区分是否已验证的场景
  78. func OptionalSecureVerification() gin.HandlerFunc {
  79. return func(c *gin.Context) {
  80. userId := c.GetInt("id")
  81. if userId == 0 {
  82. c.Set("secure_verified", false)
  83. c.Next()
  84. return
  85. }
  86. session := sessions.Default(c)
  87. verifiedAtRaw := session.Get(SecureVerificationSessionKey)
  88. if verifiedAtRaw == nil {
  89. c.Set("secure_verified", false)
  90. c.Next()
  91. return
  92. }
  93. verifiedAt, ok := verifiedAtRaw.(int64)
  94. if !ok {
  95. c.Set("secure_verified", false)
  96. c.Next()
  97. return
  98. }
  99. elapsed := time.Now().Unix() - verifiedAt
  100. if elapsed >= SecureVerificationTimeout {
  101. clearSecureVerificationSession(session)
  102. c.Set("secure_verified", false)
  103. c.Next()
  104. return
  105. }
  106. c.Set("secure_verified", true)
  107. c.Set("secure_verified_at", verifiedAt)
  108. c.Next()
  109. }
  110. }
  111. // ClearSecureVerification 清除安全验证状态
  112. // 用于用户登出或需要强制重新验证的场景
  113. func ClearSecureVerification(c *gin.Context) {
  114. session := sessions.Default(c)
  115. clearSecureVerificationSession(session)
  116. }