fix: validate app tokens via user credential
This commit is contained in:
parent
f396a19298
commit
d00216ebbc
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"chatapp3-golang/internal/config"
|
"chatapp3-golang/internal/config"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -11,6 +12,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
@ -19,8 +21,12 @@ type Client struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UserCredential struct {
|
type UserCredential struct {
|
||||||
UserID Int64Value `json:"userId"`
|
UserID Int64Value `json:"userId"`
|
||||||
SysOrigin string `json:"sysOrigin"`
|
SysOrigin string `json:"sysOrigin"`
|
||||||
|
ExpireTime Int64Value `json:"expireTime"`
|
||||||
|
ReleaseTime Int64Value `json:"releaseTime"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Sign string `json:"sign"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserProfile struct {
|
type UserProfile struct {
|
||||||
@ -113,7 +119,13 @@ func New(cfg config.Config) *Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) AuthenticateToken(ctx context.Context, token string) (UserCredential, error) {
|
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]
|
var resp resultResponse[UserCredential]
|
||||||
if err := c.getJSON(ctx, endpoint, nil, &resp); err != nil {
|
if err := c.getJSON(ctx, endpoint, nil, &resp); err != nil {
|
||||||
return UserCredential{}, err
|
return UserCredential{}, err
|
||||||
@ -121,7 +133,73 @@ func (c *Client) AuthenticateToken(ctx context.Context, token string) (UserCrede
|
|||||||
if int64(resp.Body.UserID) == 0 {
|
if int64(resp.Body.UserID) == 0 {
|
||||||
return UserCredential{}, fmt.Errorf("empty credential response")
|
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) {
|
func (c *Client) GetDeviceFingerprint(ctx context.Context, userID int64) (string, error) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user