Files
lone-services/services/user/internal/logic/response.go
T
2026-10-20 13:09:55 +08:00

273 lines
8.1 KiB
Go

package logic
import (
"context"
"strconv"
"time"
"lone-services/pkg/redis"
"lone-services/pkg/utils"
user "lone-services/rpc/user/pb"
"lone-services/services/user/internal/config"
"lone-services/services/user/internal/dao"
jsoniter "github.com/json-iterator/go"
)
func okResponse(data any) *user.Response {
buf, _ := jsoniter.Marshal(data)
return &user.Response{
Code: utils.Ok.Code,
Msg: utils.Ok.Msg,
Data: string(buf),
}
}
func failResponse(status utils.Status) *user.Response {
return &user.Response{
Code: status.Code,
Msg: status.Msg,
}
}
func outResponse(status utils.Status, msg string) *user.Response {
return &user.Response{
Code: status.Code,
Msg: msg,
}
}
func toSession(info dao.UserRow, mobilePlain string, client *dao.Client) dao.UserLoginSession {
return dao.UserLoginSession{
Id: info.Id,
Name: info.Name,
Avatar: info.Avatar,
Mobile: mobilePlain,
Gender: info.Gender,
Birthday: info.Birthday.DateString(),
Type: client.Type,
ClientCode: client.Code,
}
}
func sessionClaims(session dao.UserLoginSession, tokenType string) utils.Claims {
return utils.Claims{
UserID: session.Id,
Name: session.Name,
Avatar: session.Avatar,
Mobile: session.Mobile,
Gender: session.Gender,
Birthday: session.Birthday,
Type: session.Type,
ClientCode: session.ClientCode,
BizId: session.BizId,
TokenType: tokenType,
}
}
func buildJwtToken(jwtAuth *config.JWTAuth, session dao.UserLoginSession) (dao.Token, error) {
accessToken, err := jwtAuth.Access.Sign(sessionClaims(session, utils.TokenTypeAccess))
if err != nil {
return dao.Token{}, err
}
refreshToken, err := jwtAuth.Refresh.Sign(sessionClaims(session, utils.TokenTypeRefresh))
if err != nil {
return dao.Token{}, err
}
return dao.Token{
AccessToken: accessToken,
RefreshToken: refreshToken,
Info: session,
}, nil
}
func loginCacheType(client *dao.Client) string {
if client == nil {
return utils.LoginTypeUser
}
switch client.SubjectType {
case dao.SubjectTypeSale:
return utils.LoginTypeSale
case dao.SubjectTypeStore:
return utils.LoginTypeStore
case dao.SubjectTypeUser:
return utils.LoginTypeUser
}
switch client.Type {
case dao.TypeSale:
return utils.LoginTypeSale
case dao.TypeStore:
return utils.LoginTypeStore
default:
return utils.LoginTypeUser
}
}
func setLogin(jwtAuth *config.JWTAuth, accessToken, refreshToken string, session dao.UserLoginSession, client *dao.Client) utils.Status {
accessExpire := time.Duration(jwtAuth.Access.TTL) * time.Second
refreshExpire := time.Duration(jwtAuth.Refresh.TTL) * time.Second
loginType := loginCacheType(client)
ctx := context.Background()
userStr, _ := jsoniter.Marshal(session)
redisKey := utils.GetLoginKey(loginType, accessToken)
if err := redis.Client.Set(ctx, redisKey, userStr, accessExpire).Err(); err != nil {
return utils.Fail
}
redisKeysKey := utils.GetLoginKeysKey(loginType, strconv.FormatInt(session.Id, utils.NumberTen))
var loginInfo utils.LoginRedis
if oldAuth, err := redis.Client.Get(ctx, redisKeysKey).Result(); err == nil {
_ = jsoniter.Unmarshal([]byte(oldAuth), &loginInfo)
if len(loginInfo.Token) > utils.NumberOne {
redis.Client.Del(ctx, utils.GetLoginKey(loginType, loginInfo.Token))
}
if len(loginInfo.Refresh) > utils.NumberOne {
redis.Client.Del(ctx, utils.GetLoginRefreshKey(loginType, loginInfo.Refresh))
}
}
loginInfo.Token = accessToken
loginInfo.Refresh = refreshToken
loginInfo.Info = userStr
newStr, _ := jsoniter.Marshal(loginInfo)
if err := redis.Client.Set(ctx, redisKeysKey, newStr, refreshExpire).Err(); err != nil {
return utils.Fail
}
refreshKey := utils.GetLoginRefreshKey(loginType, refreshToken)
if err := redis.Client.Set(ctx, refreshKey, strconv.FormatInt(session.Id, utils.NumberTen), refreshExpire).Err(); err != nil {
return utils.Fail
}
return utils.Ok
}
// tryRenewUserLogin 仅对 C 端(subject_type=user)复用已有 token 并续期;
// 门店/销售不走此逻辑。成功时更新会话中的 client_code/biz_id 等字段。
func tryRenewUserLogin(jwtAuth *config.JWTAuth, session dao.UserLoginSession, client *dao.Client) (*dao.Token, bool) {
if jwtAuth == nil || jwtAuth.Access == nil || jwtAuth.Refresh == nil {
return nil, false
}
if loginCacheType(client) != utils.LoginTypeUser {
return nil, false
}
if redis.Client == nil || session.Id < utils.NumberOne {
return nil, false
}
ctx := context.Background()
loginType := utils.LoginTypeUser
infoKey := utils.GetLoginKeysKey(loginType, strconv.FormatInt(session.Id, utils.NumberTen))
oldAuth, err := redis.Client.Get(ctx, infoKey).Result()
if err != nil {
return nil, false
}
var loginInfo utils.LoginRedis
if err := jsoniter.Unmarshal([]byte(oldAuth), &loginInfo); err != nil {
return nil, false
}
if len(loginInfo.Token) <= utils.NumberOne || len(loginInfo.Refresh) <= utils.NumberOne {
return nil, false
}
tokenKey := utils.GetLoginKey(loginType, loginInfo.Token)
if _, err := redis.Client.Get(ctx, tokenKey).Result(); err != nil {
return nil, false
}
accessExpire := time.Duration(jwtAuth.Access.TTL) * time.Second
refreshExpire := time.Duration(jwtAuth.Refresh.TTL) * time.Second
userStr, _ := jsoniter.Marshal(session)
if err := redis.Client.Set(ctx, tokenKey, userStr, accessExpire).Err(); err != nil {
return nil, false
}
loginInfo.Info = userStr
newStr, _ := jsoniter.Marshal(loginInfo)
if err := redis.Client.Set(ctx, infoKey, newStr, refreshExpire).Err(); err != nil {
return nil, false
}
refreshKey := utils.GetLoginRefreshKey(loginType, loginInfo.Refresh)
if err := redis.Client.Set(ctx, refreshKey, strconv.FormatInt(session.Id, utils.NumberTen), refreshExpire).Err(); err != nil {
return nil, false
}
return &dao.Token{
AccessToken: loginInfo.Token,
RefreshToken: loginInfo.Refresh,
Info: session,
}, true
}
func remaponUserLoginAfterMerge(jwtAuth *config.JWTAuth, fromUserId, toUserId int64, session dao.UserLoginSession) error {
if jwtAuth == nil || jwtAuth.Access == nil || jwtAuth.Refresh == nil {
return nil
}
if redis.Client == nil || fromUserId < utils.NumberOne || toUserId < utils.NumberOne {
return nil
}
if session.Id != toUserId {
session.Id = toUserId
}
ctx := context.Background()
loginType := utils.LoginTypeUser
fromInfoKey := utils.GetLoginKeysKey(loginType, strconv.FormatInt(fromUserId, utils.NumberTen))
oldAuth, err := redis.Client.Get(ctx, fromInfoKey).Result()
if err != nil {
return nil
}
var loginInfo utils.LoginRedis
if err := jsoniter.Unmarshal([]byte(oldAuth), &loginInfo); err != nil {
return err
}
if len(loginInfo.Token) <= utils.NumberOne {
return nil
}
accessExpire := time.Duration(jwtAuth.Access.TTL) * time.Second
refreshExpire := time.Duration(jwtAuth.Refresh.TTL) * time.Second
userStr, _ := jsoniter.Marshal(session)
tokenKey := utils.GetLoginKey(loginType, loginInfo.Token)
if err := redis.Client.Set(ctx, tokenKey, userStr, accessExpire).Err(); err != nil {
return err
}
toInfoKey := utils.GetLoginKeysKey(loginType, strconv.FormatInt(toUserId, utils.NumberTen))
if oldTo, err := redis.Client.Get(ctx, toInfoKey).Result(); err == nil {
var toLogin utils.LoginRedis
if uErr := jsoniter.Unmarshal([]byte(oldTo), &toLogin); uErr == nil {
if len(toLogin.Token) > utils.NumberOne && toLogin.Token != loginInfo.Token {
_ = redis.Client.Del(ctx, utils.GetLoginKey(loginType, toLogin.Token)).Err()
}
if len(toLogin.Refresh) > utils.NumberOne && toLogin.Refresh != loginInfo.Refresh {
_ = redis.Client.Del(ctx, utils.GetLoginRefreshKey(loginType, toLogin.Refresh)).Err()
}
}
}
loginInfo.Info = userStr
newStr, _ := jsoniter.Marshal(loginInfo)
if err := redis.Client.Set(ctx, toInfoKey, newStr, refreshExpire).Err(); err != nil {
return err
}
if fromUserId != toUserId {
_ = redis.Client.Del(ctx, fromInfoKey).Err()
}
if len(loginInfo.Refresh) > utils.NumberOne {
refreshKey := utils.GetLoginRefreshKey(loginType, loginInfo.Refresh)
if err := redis.Client.Set(ctx, refreshKey, strconv.FormatInt(toUserId, utils.NumberTen), refreshExpire).Err(); err != nil {
return err
}
}
return nil
}