package auth import ( "context" "strconv" "testing" jwt "github.com/golang-jwt/jwt/v5" ) func TestVerifierParsesLargeUserIDStringWithoutPrecisionLoss(t *testing.T) { t.Parallel() const userID int64 = 399999999999990001 token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "user_id": strconv.FormatInt(userID, 10), "app_code": "lalu", "device_id": " device-auth-1 ", }) signed, err := token.SignedString([]byte("secret")) if err != nil { t.Fatalf("sign token failed: %v", err) } claims, err := NewVerifier("secret").Verify("Bearer " + signed) if err != nil { t.Fatalf("Verify failed: %v", err) } if claims.UserID != userID { t.Fatalf("user_id lost precision: got %d want %d", claims.UserID, userID) } if claims.DeviceID != "device-auth-1" { t.Fatalf("device_id was not normalized from signed claim: got %q", claims.DeviceID) } } func TestVerifierKeepsLegacyTokenWithoutDeviceIDCompatible(t *testing.T) { t.Parallel() // 存量 access token 在滚动升级期不携带 device_id;gateway 仍应允许其进入 fixed_v2, // 但绝不得把 sid 自动填为设备,dynamic_v3 会在 owner 处对空设备 fail-close。 token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "user_id": strconv.FormatInt(42, 10), "sid": "sess-must-not-be-device", }) signed, err := token.SignedString([]byte("secret")) if err != nil { t.Fatalf("sign legacy token failed: %v", err) } claims, err := NewVerifier("secret").Verify("Bearer " + signed) if err != nil { t.Fatalf("Verify legacy token failed: %v", err) } ctx := WithClaims(context.Background(), claims) if got := DeviceIDFromContext(ctx); got != "" { t.Fatalf("legacy token device_id=%q, want empty instead of sid fallback", got) } }