Без опису
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

token_auth_middleware.go 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. package authbase
  2. import (
  3. "fmt"
  4. "net/http"
  5. "strings"
  6. "time"
  7. "git.x2erp.com/qdy/go-base/config"
  8. "git.x2erp.com/qdy/go-base/ctx"
  9. "git.x2erp.com/qdy/go-base/logger"
  10. "git.x2erp.com/qdy/go-base/util/jwt"
  11. )
  12. // TokenAuth 简化的Bearer认证中间件
  13. func TokenAuth(next http.Handler) http.Handler {
  14. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  15. if logger.IsDebug() {
  16. logger.Debug("TokenAuth中间件开始处理请求: %s %s", r.Method, r.URL.Path)
  17. }
  18. // 1. 检查认证头
  19. authHeader := r.Header.Get("Authorization")
  20. if authHeader == "" {
  21. if logger.IsDebug() {
  22. logger.Debug("认证头缺失,请求未授权: %s %s", r.Method, r.URL.Path)
  23. }
  24. unauthorized(w, "缺少认证信息")
  25. return
  26. }
  27. if logger.IsDebug() {
  28. displayHeader := authHeader
  29. if len(displayHeader) > 20 {
  30. displayHeader = displayHeader[:20] + "..."
  31. }
  32. logger.Debug("收到认证头: %s", displayHeader)
  33. }
  34. // 2. 检查Bearer格式
  35. if !strings.HasPrefix(authHeader, "Bearer ") {
  36. if logger.IsDebug() {
  37. displayHeader := authHeader
  38. if len(displayHeader) > 20 {
  39. displayHeader = displayHeader[:20] + "..."
  40. }
  41. logger.Debug("认证格式错误,需要Bearer认证: %s", displayHeader)
  42. }
  43. unauthorized(w, "认证格式错误,请使用Bearer认证")
  44. return
  45. }
  46. // 3. 解码凭证
  47. token := strings.TrimPrefix(authHeader, "Bearer ")
  48. if logger.IsDebug() {
  49. logger.Debug("验证JWT令牌,令牌长度: %d", len(token))
  50. }
  51. // 验证JWT令牌
  52. claims, err := validToken(token)
  53. if err != nil {
  54. if logger.IsDebug() {
  55. logger.Debug("JWT令牌验证失败: %v", err)
  56. }
  57. unauthorized(w, fmt.Sprintf("Invalid token: %v", err))
  58. return
  59. }
  60. if logger.IsDebug() {
  61. logger.Debug("JWT令牌验证成功,用户: %s, 租户: %s", claims.Username, claims.TenantID)
  62. }
  63. // 6. 创建请求上下文
  64. traceID := r.Header.Get("X-Trace-ID")
  65. if traceID == "" {
  66. // 生成简单的时间戳追踪ID
  67. traceID = time.Now().Format("20060102150405.000")
  68. if logger.IsDebug() {
  69. logger.Debug("生成TraceID: %s", traceID)
  70. }
  71. } else if logger.IsDebug() {
  72. logger.Debug("使用请求中的TraceID: %s", traceID)
  73. }
  74. cfg := config.GetConfig()
  75. requestCtx := &ctx.RequestContext{
  76. ServiceName: cfg.GetServiceConfig().ServiceName,
  77. InstanceName: cfg.GetServiceConfig().InstanceName,
  78. TraceID: traceID,
  79. TenantID: claims.TenantID,
  80. UserID: claims.UserID,
  81. Username: claims.Username,
  82. ProjectID: claims.ProjectID,
  83. }
  84. if logger.IsDebug() {
  85. logger.Debug("创建请求上下文: service=%s, instance=%s, tenant=%s, user=%s",
  86. requestCtx.ServiceName, requestCtx.InstanceName, requestCtx.TenantID, requestCtx.UserID)
  87. }
  88. // 7. 保存到请求
  89. r = ctx.SaveContext(r, requestCtx)
  90. // 8. 继续处理
  91. if logger.IsDebug() {
  92. logger.Debug("TokenAuth中间件处理完成,继续下一个处理器")
  93. }
  94. next.ServeHTTP(w, r)
  95. })
  96. }
  97. // 验证令牌(需要根据实际项目实现)
  98. func validToken(token string) (*jwt.Claims, error) {
  99. secretKey := config.GetServiceConfig().SecretKey
  100. if logger.IsDebug() {
  101. logger.Debug("验证JWT令牌,secretKey长度: %d", len(secretKey))
  102. }
  103. return jwt.ParseToken(token, secretKey)
  104. }
  105. // PrintAllHeaders 打印HTTP请求的所有头部信息
  106. // func printAllHeaders(r *http.Request) {
  107. // if !logger.IsDebug() {
  108. // return
  109. // }
  110. // logger.Debug("=== HTTP 请求头 ===")
  111. // for name, values := range r.Header {
  112. // for _, value := range values {
  113. // logger.Debug("%s: %s", name, value)
  114. // }
  115. // }
  116. // logger.Debug("==================")
  117. // }
  118. // DebugPrintFullRequest 打印完整的HTTP请求信息(头+体),并确保请求体可被后续代码正常读取。
  119. // 将此函数在处理请求的最开始调用。
  120. // func debugPrintFullRequest(r *http.Request) {
  121. // if !logger.IsDebug() {
  122. // return
  123. // }
  124. // logger.Debug("🔍 [DEBUG] ====== 开始打印完整请求 ======")
  125. // // 1. 打印基本请求信息
  126. // logger.Debug("[DEBUG] 方法: %s, URL: %s, 协议: %s", r.Method, r.URL.String(), r.Proto)
  127. // // 2. 打印所有请求头
  128. // logger.Debug("[DEBUG] --- 请求头 ---")
  129. // // 按字母顺序排序输出,更易读
  130. // var headers []string
  131. // for key := range r.Header {
  132. // headers = append(headers, key)
  133. // }
  134. // sort.Strings(headers)
  135. // for _, key := range headers {
  136. // logger.Debug("[DEBUG] %s: %s", key, strings.Join(r.Header[key], ", "))
  137. // }
  138. // // 3. 【核心】读取、打印并恢复请求体
  139. // logger.Debug("[DEBUG] --- 请求体 (原始) ---")
  140. // if r.Body == nil || r.ContentLength == 0 {
  141. // logger.Debug("[DEBUG] 请求体为空")
  142. // } else {
  143. // // 读取原始Body内容
  144. // originalBodyBytes, err := io.ReadAll(r.Body)
  145. // if err != nil {
  146. // logger.Debug("[DEBUG] 读取请求体失败: %v", err)
  147. // // 即使失败,也要尝试恢复一个空Body,避免后续panic
  148. // r.Body = io.NopCloser(bytes.NewBuffer(nil))
  149. // return
  150. // }
  151. // // 重要:立即关闭原Body流
  152. // r.Body.Close()
  153. // // 打印原始内容
  154. // logger.Debug("[DEBUG] 内容长度: %d 字节", len(originalBodyBytes))
  155. // logger.Debug(string(originalBodyBytes))
  156. // // 【关键步骤】将读取的字节重新设置回 r.Body,供后续使用
  157. // r.Body = io.NopCloser(bytes.NewBuffer(originalBodyBytes))
  158. // // 4. (可选)尝试美化打印JSON,便于阅读
  159. // logger.Debug("[DEBUG] --- 请求体 (JSON美化) ---")
  160. // if len(originalBodyBytes) > 0 {
  161. // var prettyJSON bytes.Buffer
  162. // if err := json.Indent(&prettyJSON, originalBodyBytes, "", " "); err == nil {
  163. // // 是有效的JSON
  164. // logger.Debug(prettyJSON.String())
  165. // } else {
  166. // // 不是JSON或格式错误,打印原始内容
  167. // logger.Debug("[DEBUG] 内容非JSON格式,上方已打印原始内容。")
  168. // }
  169. // }
  170. // }
  171. // logger.Debug("🔍 [DEBUG] ====== 结束打印 ======\n")
  172. // }