Skip to content

Commit a4067a6

Browse files
committed
feat(auth): 增强OAuth用户信息解析和处理逻辑
- 重构用户信息解析方法,支持更多JSON字段和灵活的用户名提取 - 添加调试日志记录用户信息响应内容 - 优化用户名提取策略,支持多种备用字段 - 增加头像URL的多字段兼容处理 - 改进用户信息验证和错误处理机制 - 扩展 OAuthUserInfo 结构体,支持更多可选字段
1 parent 0d10e89 commit a4067a6

File tree

2 files changed

+66
-13
lines changed

2 files changed

+66
-13
lines changed

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ services:
99
environment:
1010
- TZ=Asia/Shanghai
1111
- OAUTH_CLIENT_ID=your_client_id
12+
- OAUTH_CLIENT_SECRET=your_client_secret
1213
restart: always

internal/handler/auth.go

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/base64"
66
"encoding/json"
77
"fmt"
8+
"io"
89
"log"
910
"net/http"
1011
"net/url"
@@ -20,14 +21,23 @@ const (
2021
)
2122

2223
type OAuthUserInfo struct {
23-
ID string `json:"id"`
24-
Email string `json:"email"`
25-
Username string `json:"username"`
26-
Name string `json:"name"`
27-
AvatarURL string `json:"avatar_url"`
28-
Admin bool `json:"admin"`
29-
Moderator bool `json:"moderator"`
30-
Groups []string `json:"groups"`
24+
ID interface{} `json:"id,omitempty"` // 使用interface{}以接受数字或字符串
25+
Email string `json:"email,omitempty"`
26+
Username string `json:"username,omitempty"`
27+
Name string `json:"name,omitempty"`
28+
AvatarURL string `json:"avatar_url,omitempty"`
29+
Avatar string `json:"avatar,omitempty"` // 添加avatar字段
30+
Admin bool `json:"admin,omitempty"`
31+
Moderator bool `json:"moderator,omitempty"`
32+
Groups []string `json:"groups,omitempty"`
33+
Upstreams interface{} `json:"upstreams,omitempty"` // 添加upstreams字段
34+
35+
// 添加可能的替代字段名
36+
Sub string `json:"sub,omitempty"`
37+
PreferredName string `json:"preferred_username,omitempty"`
38+
GivenName string `json:"given_name,omitempty"`
39+
FamilyName string `json:"family_name,omitempty"`
40+
Picture string `json:"picture,omitempty"`
3141
}
3242

3343
type OAuthToken struct {
@@ -255,17 +265,59 @@ func (h *ProxyHandler) OAuthCallbackHandler(w http.ResponseWriter, r *http.Reque
255265
return
256266
}
257267

258-
var userInfo OAuthUserInfo
259-
if err := json.NewDecoder(userResp.Body).Decode(&userInfo); err != nil {
260-
log.Printf("[Auth] ERR %s %s -> 500 (%s) failed to parse user info: %v from %s", r.Method, r.URL.Path, utils.GetClientIP(r), err, utils.GetRequestSource(r))
268+
// 读取响应体内容并记录
269+
bodyBytes, err := io.ReadAll(userResp.Body)
270+
if err != nil {
271+
log.Printf("[Auth] ERR %s %s -> 500 (%s) failed to read user info response body: %v from %s",
272+
r.Method, r.URL.Path, utils.GetClientIP(r), err, utils.GetRequestSource(r))
273+
http.Error(w, "Failed to read user info response", http.StatusInternalServerError)
274+
return
275+
}
276+
277+
// 记录响应内容(小心敏感信息)
278+
log.Printf("[Auth] DEBUG %s %s -> user info response: %s", r.Method, r.URL.Path, string(bodyBytes))
279+
280+
// 使用更灵活的方式解析JSON
281+
var rawUserInfo map[string]interface{}
282+
if err := json.Unmarshal(bodyBytes, &rawUserInfo); err != nil {
283+
log.Printf("[Auth] ERR %s %s -> 500 (%s) failed to parse raw user info: %v from %s",
284+
r.Method, r.URL.Path, utils.GetClientIP(r), err, utils.GetRequestSource(r))
261285
http.Error(w, "Failed to parse user info", http.StatusInternalServerError)
262286
return
263287
}
264288

289+
// 创建用户信息对象
290+
userInfo := OAuthUserInfo{}
291+
292+
// 填充用户名(优先级:username > preferred_username > sub > email)
293+
if username, ok := rawUserInfo["username"].(string); ok && username != "" {
294+
userInfo.Username = username
295+
} else if preferred, ok := rawUserInfo["preferred_username"].(string); ok && preferred != "" {
296+
userInfo.Username = preferred
297+
} else if sub, ok := rawUserInfo["sub"].(string); ok && sub != "" {
298+
userInfo.Username = sub
299+
} else if email, ok := rawUserInfo["email"].(string); ok && email != "" {
300+
// 从邮箱中提取用户名
301+
parts := strings.Split(email, "@")
302+
if len(parts) > 0 {
303+
userInfo.Username = parts[0]
304+
}
305+
}
306+
307+
// 填充头像URL
308+
if avatar, ok := rawUserInfo["avatar"].(string); ok && avatar != "" {
309+
userInfo.Avatar = avatar
310+
} else if avatarURL, ok := rawUserInfo["avatar_url"].(string); ok && avatarURL != "" {
311+
userInfo.AvatarURL = avatarURL
312+
} else if picture, ok := rawUserInfo["picture"].(string); ok && picture != "" {
313+
userInfo.Picture = picture
314+
}
315+
265316
// 验证用户信息
266317
if userInfo.Username == "" {
267-
log.Printf("[Auth] ERR %s %s -> 500 (%s) received invalid user info (missing username) from %s", r.Method, r.URL.Path, utils.GetClientIP(r), utils.GetRequestSource(r))
268-
http.Error(w, "Invalid user information", http.StatusInternalServerError)
318+
log.Printf("[Auth] ERR %s %s -> 500 (%s) could not extract username from user info from %s",
319+
r.Method, r.URL.Path, utils.GetClientIP(r), utils.GetRequestSource(r))
320+
http.Error(w, "Invalid user information: missing username", http.StatusInternalServerError)
269321
return
270322
}
271323

0 commit comments

Comments
 (0)