secure_verification.go 3.2 KB

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