2026-07-12 14:17:45 +08:00

74 lines
3.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package auth
import (
"context"
"log/slog"
"strings"
"hyapp/pkg/appcode"
"hyapp/pkg/logx"
authdomain "hyapp/services/user-service/internal/domain/auth"
)
// recordUserDevice 在认证成功后合并当前设备档案。
// 该写入是 best-effortdevice_id 为空(老客户端/后台调用)直接跳过;写失败只记日志,
// 绝不让已经成功的登录/注册/refresh 因为设备画像落库失败而回吐错误。
func (s *Service) recordUserDevice(ctx context.Context, meta Meta, userID int64, deviceID string) {
deviceID = strings.TrimSpace(deviceID)
if s.authRepository == nil || userID <= 0 || deviceID == "" {
return
}
nowMs := s.now().UnixMilli()
device := authdomain.UserDevice{
AppCode: appcode.Normalize(meta.AppCode),
UserID: userID,
DeviceID: truncateDeviceField(deviceID, 128),
Platform: truncateDeviceField(normalizePlatform(meta.Platform), 32),
DeviceModel: truncateDeviceField(meta.DeviceModel, 128),
Manufacturer: truncateDeviceField(meta.DeviceManufacturer, 64),
OSVersion: truncateDeviceField(meta.OSVersion, 64),
IMEI: truncateDeviceField(meta.IMEI, 64),
AppVersion: normalizeAuditClientVersion(meta.AppVersion),
BuildNumber: normalizeAuditClientVersion(meta.BuildNumber),
// first_seen 只在 INSERT 生效ON DUPLICATE KEY 更新时只有 last_seen/updated 前移。
FirstSeenAtMs: nowMs,
LastSeenAtMs: nowMs,
CreatedAtMs: nowMs,
UpdatedAtMs: nowMs,
}
if err := s.authRepository.UpsertUserDevice(ctx, device); err != nil {
// 失败必须可见:设备 tab 静默缺数据比登录多一条错误日志更难排查。
logx.Error(
logx.With(ctx, slog.String("request_id", meta.RequestID), slog.String("app_code", device.AppCode)),
"user_device_upsert_failed",
err,
slog.String("component", "user_auth"),
slog.Int64("user_id", userID),
slog.String("device_id", device.DeviceID),
)
}
}
// deviceMetaWithRegistration 用注册 body 的设备字段补齐 Meta 缺口。
// 设备资料有两个来源gateway 设备头(新客户端全局注入)和注册 body旧协议字段
// 任意一侧可能单独缺失,落档案前统一取“先 header 后 body”的非空值。
func deviceMetaWithRegistration(meta Meta, registration authdomain.ThirdPartyRegistration) Meta {
meta.Platform = firstNonEmpty(meta.Platform, registration.Platform)
meta.DeviceModel = firstNonEmpty(meta.DeviceModel, registration.Device)
meta.OSVersion = firstNonEmpty(meta.OSVersion, registration.OSVersion)
meta.AppVersion = firstNonEmpty(meta.AppVersion, registration.AppVersion)
meta.BuildNumber = firstNonEmpty(meta.BuildNumber, registration.BuildNumber)
return meta
}
// truncateDeviceField 按列宽截断客户端可控字符串,超长上报不能让整条设备档案 INSERT 失败。
func truncateDeviceField(value string, maxRunes int) string {
value = strings.TrimSpace(value)
runes := []rune(value)
if len(runes) <= maxRunes {
return value
}
return string(runes[:maxRunes])
}