package service import ( "encoding/json" "fmt" "io" "net/http" "net/http/cookiejar" "net/url" "strings" ) // TokenResponse 用来解析第一次请求返回的 JSON type TokenResponse struct { Token string `json:"token"` UserID int `json:"userId"` } // UserResponse 最外层响应 type UserResponse struct { Data UserData `json:"data"` Included []Group `json:"included"` } // UserData 用户数据 type UserData struct { Type string `json:"type"` ID string `json:"id"` Attributes UserAttributes `json:"attributes"` Relationships Relationships `json:"relationships"` } // UserAttributes 用户详细属性 type UserAttributes struct { Username string `json:"username"` DisplayName string `json:"displayName"` AvatarUrl string `json:"avatarUrl"` Slug string `json:"slug"` JoinTime string `json:"joinTime"` DiscussionCount int `json:"discussionCount"` CommentCount int `json:"commentCount"` CanEdit bool `json:"canEdit"` CanEditCredentials bool `json:"canEditCredentials"` CanEditGroups bool `json:"canEditGroups"` CanDelete bool `json:"canDelete"` LastSeenAt string `json:"lastSeenAt"` Achievements []string `json:"achievements"` Followed *bool `json:"followed"` // 可能为 null FollowerCount int `json:"followerCount"` FollowingCount int `json:"followingCount"` Money float64 `json:"money"` CanEditMoney bool `json:"canEditMoney"` CanSuspend bool `json:"canSuspend"` LastCheckinTime string `json:"lastCheckinTime"` TotalContinuousCheckIn int `json:"totalContinuousCheckIn"` CheckInCompatibleExtensions []string `json:"checkInCompatibleExtensions"` CanCheckin bool `json:"canCheckin"` CanCheckinContinuous bool `json:"canCheckinContinuous"` CanBeFollowed bool `json:"canBeFollowed"` FofUploadUploadCountCurrent int `json:"fof-upload-uploadCountCurrent"` FofUploadUploadCountAll int `json:"fof-upload-uploadCountAll"` BestAnswerCount int `json:"bestAnswerCount"` IsBanned bool `json:"isBanned"` CanBanIP bool `json:"canBanIP"` CanEditNickname bool `json:"canEditNickname"` } // Relationships 用户关系 type Relationships struct { Groups RelationshipData `json:"groups"` Achievements RelationshipData `json:"achievements"` } // RelationshipData 关系数据 type RelationshipData struct { Data []RelationshipItem `json:"data"` } // RelationshipItem 关系项 type RelationshipItem struct { Type string `json:"type"` ID string `json:"id"` } // Group 组信息 type Group struct { Type string `json:"type"` ID string `json:"id"` Attributes GroupAttributes `json:"attributes"` } // GroupAttributes 组属性 type GroupAttributes struct { NameSingular string `json:"nameSingular"` NamePlural string `json:"namePlural"` Color string `json:"color"` Icon string `json:"icon"` IsHidden int `json:"isHidden"` } var bbsurl = "http://43.248.3.21:45632" // GetUserInfo 输入用户名和密码,返回用户信息结构体 func GetUserInfo(username, password string) (*UserResponse, error) { // 创建带 Cookie 存储的 HTTP 客户端 jar, err := cookiejar.New(nil) if err != nil { return nil, fmt.Errorf("创建 CookieJar 失败: %w", err) } client := &http.Client{Jar: jar} // 1. POST 获取 token tokenURL := bbsurl + "/api/token" formData := url.Values{} formData.Set("identification", username) formData.Set("password", password) req, err := http.NewRequest("POST", tokenURL, strings.NewReader(formData.Encode())) if err != nil { return nil, fmt.Errorf("创建请求失败: %w", err) } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") resp, err := client.Do(req) if err != nil { return nil, fmt.Errorf("发送请求失败: %w", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("读取响应失败: %w", err) } // 解析 token var tokenResp TokenResponse err = json.Unmarshal(body, &tokenResp) if err != nil { return nil, fmt.Errorf("解析 token 失败: %w", err) } // 提取 CSRF Token csrfToken := resp.Header.Get("X-CSRF-Token") // 2. GET 获取该用户的详细信息 usersURL := bbsurl + fmt.Sprintf("/api/users/%d", tokenResp.UserID) req2, err := http.NewRequest("GET", usersURL, nil) if err != nil { return nil, fmt.Errorf("创建请求失败: %w", err) } req2.Header.Set("Authentication", tokenResp.Token) req2.Header.Set("X-CSRF-Token", csrfToken) resp2, err := client.Do(req2) if err != nil { return nil, fmt.Errorf("发送请求失败: %w", err) } defer resp2.Body.Close() body2, err := io.ReadAll(resp2.Body) if err != nil { return nil, fmt.Errorf("读取响应失败: %w", err) } // 解析用户信息 var userResp UserResponse err = json.Unmarshal(body2, &userResp) if err != nil { return nil, fmt.Errorf("解析用户信息失败: %w", err) } return &userResp, nil }