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