手机号适配双端

This commit is contained in:
2025-06-18 16:31:32 +08:00
parent a738c711de
commit 301a80447d
39 changed files with 1423 additions and 1348 deletions

View File

@@ -5,14 +5,16 @@ import (
"encoding/json"
"errors"
"fmt"
"tydata-server/app/main/model"
jwtx "tydata-server/common/jwt"
)
const CtxKeyJwtUserId = "userId"
// 定义错误类型
var (
ErrNoUserIdInCtx = errors.New("上下文中没有用户ID") // 未登录
ErrInvalidUserId = errors.New("用户ID格式无效") // 数据异常
ErrNoInCtx = errors.New("上下文中没有相关数据")
ErrInvalidUserId = errors.New("用户ID格式无效") // 数据异常
)
// GetUidFromCtx 从 context 中获取用户 ID
@@ -20,7 +22,11 @@ func GetUidFromCtx(ctx context.Context) (int64, error) {
// 尝试从上下文中获取 jwtUserId
value := ctx.Value(CtxKeyJwtUserId)
if value == nil {
return 0, ErrNoUserIdInCtx
claims, err := GetClaimsFromCtx(ctx)
if err != nil {
return 0, err
}
return claims.UserId, nil
}
// 根据值的类型进行不同处理
@@ -47,12 +53,52 @@ func GetUidFromCtx(ctx context.Context) (int64, error) {
}
}
func GetClaimsFromCtx(ctx context.Context) (*jwtx.JwtClaims, error) {
value := ctx.Value(jwtx.ExtraKey)
if value == nil {
return nil, ErrNoInCtx
}
// 首先尝试直接断言为 *jwtx.JwtClaims
if claims, ok := value.(*jwtx.JwtClaims); ok {
return claims, nil
}
// 如果直接断言失败,尝试从 map[string]interface{} 中解析
if claimsMap, ok := value.(map[string]interface{}); ok {
return jwtx.MapToJwtClaims(claimsMap)
}
return nil, ErrNoInCtx
}
// IsNoUserIdError 判断是否是未登录错误
func IsNoUserIdError(err error) bool {
return errors.Is(err, ErrNoUserIdInCtx)
return errors.Is(err, ErrNoInCtx)
}
// IsInvalidUserIdError 判断是否是用户ID格式错误
func IsInvalidUserIdError(err error) bool {
return errors.Is(err, ErrInvalidUserId)
}
// GetPlatformFromCtx 从 context 中获取平台
func GetPlatformFromCtx(ctx context.Context) (string, error) {
platform, platformOk := ctx.Value("platform").(string)
if !platformOk {
return "", fmt.Errorf("平台不存在: %s", platform)
}
switch platform {
case model.PlatformWxMini:
return model.PlatformWxMini, nil
case model.PlatformWxH5:
return model.PlatformWxH5, nil
case model.PlatformApp:
return model.PlatformApp, nil
case model.PlatformH5:
return model.PlatformH5, nil
default:
return "", fmt.Errorf("不支持的支付平台: %s", platform)
}
}

View File

@@ -1,179 +0,0 @@
package ctxdata
import (
"context"
"encoding/json"
"errors"
"testing"
)
func TestGetUidFromCtx(t *testing.T) {
tests := []struct {
name string
ctxSetup func() context.Context
wantUid int64
wantError error
}{
{
name: "正常情况_有效用户ID_json.Number",
ctxSetup: func() context.Context {
return context.WithValue(context.Background(), CtxKeyJwtUserId, json.Number("12345"))
},
wantUid: 12345,
wantError: nil,
},
{
name: "正常情况_有效用户ID_int64",
ctxSetup: func() context.Context {
return context.WithValue(context.Background(), CtxKeyJwtUserId, int64(12345))
},
wantUid: 12345,
wantError: nil,
},
{
name: "正常情况_有效用户ID_int",
ctxSetup: func() context.Context {
return context.WithValue(context.Background(), CtxKeyJwtUserId, 12345)
},
wantUid: 12345,
wantError: nil,
},
{
name: "正常情况_有效用户ID_float64",
ctxSetup: func() context.Context {
return context.WithValue(context.Background(), CtxKeyJwtUserId, float64(12345))
},
wantUid: 12345,
wantError: nil,
},
{
name: "异常情况_上下文中无用户ID",
ctxSetup: func() context.Context {
return context.Background()
},
wantUid: 0,
wantError: ErrNoUserIdInCtx,
},
{
name: "异常情况_用户ID类型错误",
ctxSetup: func() context.Context {
return context.WithValue(context.Background(), CtxKeyJwtUserId, "非数字类型")
},
wantUid: 0,
wantError: ErrInvalidUserId,
},
{
name: "异常情况_用户ID无法转换为int64",
ctxSetup: func() context.Context {
return context.WithValue(context.Background(), CtxKeyJwtUserId, json.Number("非数字内容"))
},
wantUid: 0,
wantError: ErrInvalidUserId,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := tt.ctxSetup()
gotUid, gotErr := GetUidFromCtx(ctx)
// 检查返回的用户ID
if gotUid != tt.wantUid {
t.Errorf("GetUidFromCtx() 返回用户ID = %v, 期望值 %v", gotUid, tt.wantUid)
}
// 检查错误类型
if tt.wantError == nil && gotErr != nil {
t.Errorf("GetUidFromCtx() 返回意外错误 = %v", gotErr)
}
if tt.wantError != nil && !errors.Is(gotErr, tt.wantError) {
t.Errorf("GetUidFromCtx() 错误类型 = %v, 期望错误类型 %v", gotErr, tt.wantError)
}
})
}
}
func TestIsNoUserIdError(t *testing.T) {
tests := []struct {
name string
err error
expected bool
}{
{
name: "是未登录错误",
err: ErrNoUserIdInCtx,
expected: true,
},
{
name: "包装的未登录错误",
err: errors.New("外层错误: " + ErrNoUserIdInCtx.Error()),
expected: false, // 直接字符串拼接不会保留错误链
},
{
name: "使用fmt.Errorf包装的未登录错误",
err: errors.New("外层错误"),
expected: false,
},
{
name: "非未登录错误",
err: ErrInvalidUserId,
expected: false,
},
{
name: "nil错误",
err: nil,
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsNoUserIdError(tt.err); got != tt.expected {
t.Errorf("IsNoUserIdError() = %v, 期望值 %v", got, tt.expected)
}
})
}
}
func TestIsInvalidUserIdError(t *testing.T) {
tests := []struct {
name string
err error
expected bool
}{
{
name: "是无效用户ID错误",
err: ErrInvalidUserId,
expected: true,
},
{
name: "包装的无效用户ID错误",
err: errors.New("外层错误: " + ErrInvalidUserId.Error()),
expected: false, // 直接字符串拼接不会保留错误链
},
{
name: "使用fmt.Errorf包装的无效用户ID错误",
err: errors.New("外层错误"),
expected: false,
},
{
name: "非无效用户ID错误",
err: ErrNoUserIdInCtx,
expected: false,
},
{
name: "nil错误",
err: nil,
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsInvalidUserIdError(tt.err); got != tt.expected {
t.Errorf("IsInvalidUserIdError() = %v, 期望值 %v", got, tt.expected)
}
})
}
}