mirror of
https://github.com/woodchen-ink/proxy-go.git
synced 2025-07-19 17:01:56 +08:00
feat(auth): 增强OAuth用户信息解析和处理逻辑
- 重构用户信息解析方法,支持更多JSON字段和灵活的用户名提取 - 添加调试日志记录用户信息响应内容 - 优化用户名提取策略,支持多种备用字段 - 增加头像URL的多字段兼容处理 - 改进用户信息验证和错误处理机制 - 扩展 OAuthUserInfo 结构体,支持更多可选字段
This commit is contained in:
parent
0d10e89a0b
commit
a4067a6c66
@ -9,4 +9,5 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
- TZ=Asia/Shanghai
|
- TZ=Asia/Shanghai
|
||||||
- OAUTH_CLIENT_ID=your_client_id
|
- OAUTH_CLIENT_ID=your_client_id
|
||||||
|
- OAUTH_CLIENT_SECRET=your_client_secret
|
||||||
restart: always
|
restart: always
|
@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -20,14 +21,23 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type OAuthUserInfo struct {
|
type OAuthUserInfo struct {
|
||||||
ID string `json:"id"`
|
ID interface{} `json:"id,omitempty"` // 使用interface{}以接受数字或字符串
|
||||||
Email string `json:"email"`
|
Email string `json:"email,omitempty"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username,omitempty"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name,omitempty"`
|
||||||
AvatarURL string `json:"avatar_url"`
|
AvatarURL string `json:"avatar_url,omitempty"`
|
||||||
Admin bool `json:"admin"`
|
Avatar string `json:"avatar,omitempty"` // 添加avatar字段
|
||||||
Moderator bool `json:"moderator"`
|
Admin bool `json:"admin,omitempty"`
|
||||||
Groups []string `json:"groups"`
|
Moderator bool `json:"moderator,omitempty"`
|
||||||
|
Groups []string `json:"groups,omitempty"`
|
||||||
|
Upstreams interface{} `json:"upstreams,omitempty"` // 添加upstreams字段
|
||||||
|
|
||||||
|
// 添加可能的替代字段名
|
||||||
|
Sub string `json:"sub,omitempty"`
|
||||||
|
PreferredName string `json:"preferred_username,omitempty"`
|
||||||
|
GivenName string `json:"given_name,omitempty"`
|
||||||
|
FamilyName string `json:"family_name,omitempty"`
|
||||||
|
Picture string `json:"picture,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OAuthToken struct {
|
type OAuthToken struct {
|
||||||
@ -255,17 +265,59 @@ func (h *ProxyHandler) OAuthCallbackHandler(w http.ResponseWriter, r *http.Reque
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var userInfo OAuthUserInfo
|
// 读取响应体内容并记录
|
||||||
if err := json.NewDecoder(userResp.Body).Decode(&userInfo); err != nil {
|
bodyBytes, err := io.ReadAll(userResp.Body)
|
||||||
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))
|
if err != nil {
|
||||||
|
log.Printf("[Auth] ERR %s %s -> 500 (%s) failed to read user info response body: %v from %s",
|
||||||
|
r.Method, r.URL.Path, utils.GetClientIP(r), err, utils.GetRequestSource(r))
|
||||||
|
http.Error(w, "Failed to read user info response", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录响应内容(小心敏感信息)
|
||||||
|
log.Printf("[Auth] DEBUG %s %s -> user info response: %s", r.Method, r.URL.Path, string(bodyBytes))
|
||||||
|
|
||||||
|
// 使用更灵活的方式解析JSON
|
||||||
|
var rawUserInfo map[string]interface{}
|
||||||
|
if err := json.Unmarshal(bodyBytes, &rawUserInfo); err != nil {
|
||||||
|
log.Printf("[Auth] ERR %s %s -> 500 (%s) failed to parse raw user info: %v from %s",
|
||||||
|
r.Method, r.URL.Path, utils.GetClientIP(r), err, utils.GetRequestSource(r))
|
||||||
http.Error(w, "Failed to parse user info", http.StatusInternalServerError)
|
http.Error(w, "Failed to parse user info", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 创建用户信息对象
|
||||||
|
userInfo := OAuthUserInfo{}
|
||||||
|
|
||||||
|
// 填充用户名(优先级:username > preferred_username > sub > email)
|
||||||
|
if username, ok := rawUserInfo["username"].(string); ok && username != "" {
|
||||||
|
userInfo.Username = username
|
||||||
|
} else if preferred, ok := rawUserInfo["preferred_username"].(string); ok && preferred != "" {
|
||||||
|
userInfo.Username = preferred
|
||||||
|
} else if sub, ok := rawUserInfo["sub"].(string); ok && sub != "" {
|
||||||
|
userInfo.Username = sub
|
||||||
|
} else if email, ok := rawUserInfo["email"].(string); ok && email != "" {
|
||||||
|
// 从邮箱中提取用户名
|
||||||
|
parts := strings.Split(email, "@")
|
||||||
|
if len(parts) > 0 {
|
||||||
|
userInfo.Username = parts[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 填充头像URL
|
||||||
|
if avatar, ok := rawUserInfo["avatar"].(string); ok && avatar != "" {
|
||||||
|
userInfo.Avatar = avatar
|
||||||
|
} else if avatarURL, ok := rawUserInfo["avatar_url"].(string); ok && avatarURL != "" {
|
||||||
|
userInfo.AvatarURL = avatarURL
|
||||||
|
} else if picture, ok := rawUserInfo["picture"].(string); ok && picture != "" {
|
||||||
|
userInfo.Picture = picture
|
||||||
|
}
|
||||||
|
|
||||||
// 验证用户信息
|
// 验证用户信息
|
||||||
if userInfo.Username == "" {
|
if userInfo.Username == "" {
|
||||||
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))
|
log.Printf("[Auth] ERR %s %s -> 500 (%s) could not extract username from user info from %s",
|
||||||
http.Error(w, "Invalid user information", http.StatusInternalServerError)
|
r.Method, r.URL.Path, utils.GetClientIP(r), utils.GetRequestSource(r))
|
||||||
|
http.Error(w, "Invalid user information: missing username", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user