fix: validate app tokens via user credential

This commit is contained in:
hy001 2026-04-15 22:39:57 +08:00
parent f396a19298
commit d00216ebbc

View File

@ -4,6 +4,7 @@ import (
"bytes"
"chatapp3-golang/internal/config"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
@ -11,6 +12,7 @@ import (
"net/url"
"strconv"
"strings"
"time"
)
type Client struct {
@ -19,8 +21,12 @@ type Client struct {
}
type UserCredential struct {
UserID Int64Value `json:"userId"`
SysOrigin string `json:"sysOrigin"`
UserID Int64Value `json:"userId"`
SysOrigin string `json:"sysOrigin"`
ExpireTime Int64Value `json:"expireTime"`
ReleaseTime Int64Value `json:"releaseTime"`
Version string `json:"version"`
Sign string `json:"sign"`
}
type UserProfile struct {
@ -113,7 +119,13 @@ func New(cfg config.Config) *Client {
}
func (c *Client) AuthenticateToken(ctx context.Context, token string) (UserCredential, error) {
endpoint := c.cfg.JavaAuthBaseURL + "/auth/client/getUserCredentialByToken?token=" + url.QueryEscape(token)
tokenCredential, err := parseUserCredentialToken(token)
if err != nil {
return UserCredential{}, err
}
endpoint := c.cfg.JavaAuthBaseURL + "/auth/client/getUserCredential?userId=" +
url.QueryEscape(strconv.FormatInt(int64(tokenCredential.UserID), 10))
var resp resultResponse[UserCredential]
if err := c.getJSON(ctx, endpoint, nil, &resp); err != nil {
return UserCredential{}, err
@ -121,7 +133,73 @@ func (c *Client) AuthenticateToken(ctx context.Context, token string) (UserCrede
if int64(resp.Body.UserID) == 0 {
return UserCredential{}, fmt.Errorf("empty credential response")
}
return resp.Body, nil
if strings.TrimSpace(resp.Body.Sign) == "" {
return UserCredential{}, fmt.Errorf("empty credential sign")
}
if !strings.EqualFold(strings.TrimSpace(resp.Body.Sign), strings.TrimSpace(tokenCredential.Sign)) {
return UserCredential{}, fmt.Errorf("credential sign mismatch")
}
if strings.TrimSpace(resp.Body.SysOrigin) != "" && !strings.EqualFold(resp.Body.SysOrigin, tokenCredential.SysOrigin) {
return UserCredential{}, fmt.Errorf("credential sysOrigin mismatch")
}
return tokenCredential, nil
}
func parseUserCredentialToken(token string) (UserCredential, error) {
token = strings.TrimSpace(token)
if token == "" {
return UserCredential{}, fmt.Errorf("token is blank")
}
parts := strings.SplitN(token, ".", 2)
if len(parts) != 2 {
return UserCredential{}, fmt.Errorf("invalid token format")
}
sign := strings.TrimSpace(parts[0])
if sign == "" {
return UserCredential{}, fmt.Errorf("invalid token sign")
}
decoded, err := base64.StdEncoding.DecodeString(parts[1])
if err != nil {
return UserCredential{}, fmt.Errorf("decode token payload: %w", err)
}
payload, err := url.QueryUnescape(string(decoded))
if err != nil {
return UserCredential{}, fmt.Errorf("unescape token payload: %w", err)
}
items := strings.Split(payload, ":")
if len(items) != 5 {
return UserCredential{}, fmt.Errorf("invalid token payload")
}
userID, err := strconv.ParseInt(strings.TrimSpace(items[1]), 10, 64)
if err != nil {
return UserCredential{}, fmt.Errorf("invalid token userId: %w", err)
}
expireTime, err := strconv.ParseInt(strings.TrimSpace(items[3]), 10, 64)
if err != nil {
return UserCredential{}, fmt.Errorf("invalid token expireTime: %w", err)
}
releaseTime, err := strconv.ParseInt(strings.TrimSpace(items[4]), 10, 64)
if err != nil {
return UserCredential{}, fmt.Errorf("invalid token releaseTime: %w", err)
}
if expireTime <= time.Now().UnixMilli() {
return UserCredential{}, fmt.Errorf("token expired")
}
return UserCredential{
UserID: Int64Value(userID),
SysOrigin: strings.TrimSpace(items[2]),
ExpireTime: Int64Value(expireTime),
ReleaseTime: Int64Value(releaseTime),
Version: strings.TrimSpace(items[0]),
Sign: sign,
}, nil
}
func (c *Client) GetDeviceFingerprint(ctx context.Context, userID int64) (string, error) {