feat(interaction): 支持游客互动与登录合并

This commit is contained in:
Zhou Weidong committed 2026-10-26 22:34:14 +08:00
1 parent 2fe24b9db7
commit 4b0fbd73d3
41 files changed
+1207 -90

No files matched your search

@@ -0,0 +1,7 @@
// Author: fruit.com.cn
package com.fruitshorts.user.event;
/** 登录/注册成功后,在同一事务内触发设备互动合并。 */
public record AppInteractionMergeRequested(Long userId, String deviceId) {
}
@@ -25,8 +25,10 @@ import com.fruitshorts.user.vo.LoginReqVO;
import com.fruitshorts.user.vo.LogoutReqVO;
import com.fruitshorts.user.vo.RegisterReqVO;
import com.fruitshorts.user.vo.TokenRespVO;
import com.fruitshorts.user.event.AppInteractionMergeRequested;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@@ -63,6 +65,7 @@ public class AppAuthService {
private final PasswordEncoder passwordEncoder;
private final ConfigService configService;
private final GoogleIdTokenVerifier googleVerifier;
private final ApplicationEventPublisher eventPublisher;
/** 后台 sys_config 缺失或非法时使用;小于等于 0 表示不限制。 */
@Value("${fruitshorts.auth.register-max-per-ip-per-day:5}")
@@ -130,6 +133,7 @@ public class AppAuthService {
TokenRespVO resp = issueTokens(user, credential, req.getDeviceId(), req.getDeviceModel(),
req.getOsVersion(), req.getAppVersion(), req.getPlatform(), clientIp);
resp.setNewUser(true);
requestInteractionMerge(user.getId(), req.getDeviceId());
return resp;
}
@@ -177,8 +181,10 @@ public class AppAuthService {
appUserMapper.updateById(user);
touchDevice(user.getId(), req.getDeviceId(), req.getPlatform(), req.getDeviceModel());
return issueTokens(user, credential, req.getDeviceId(), req.getDeviceModel(), req.getOsVersion(),
req.getAppVersion(), req.getPlatform(), clientIp);
TokenRespVO resp = issueTokens(user, credential, req.getDeviceId(), req.getDeviceModel(),
req.getOsVersion(), req.getAppVersion(), req.getPlatform(), clientIp);
requestInteractionMerge(user.getId(), req.getDeviceId());
return resp;
}
/**
@@ -188,7 +194,7 @@ public class AppAuthService {
* 再落一条 GOOGLE 凭证用于下次直接登录;已有邮箱账号时只补 GOOGLE 凭证,不重复建号。
*/
@Transactional(rollbackFor = Exception.class)
public TokenRespVO googleLogin(String idToken) {
public TokenRespVO googleLogin(String idToken, String deviceId) {
GoogleUser googleUser = googleVerifier.verify(idToken);
String email = requireEmail(googleUser);
AppUserCredential googleCredential = findCredential(CredentialType.GOOGLE.name(), email);
@@ -215,8 +221,10 @@ public class AppAuthService {
user.setLastLoginAt(LocalDateTime.now());
user.setLastLoginIp("");
appUserMapper.updateById(user);
TokenRespVO resp = issueTokens(user, googleCredential, null, null, null, null, null, null);
touchDevice(user.getId(), deviceId, null, null);
TokenRespVO resp = issueTokens(user, googleCredential, deviceId, null, null, null, null, null);
resp.setNewUser(newUser);
requestInteractionMerge(user.getId(), deviceId);
return resp;
}
@@ -436,6 +444,13 @@ public class AppAuthService {
return resp;
}
private void requestInteractionMerge(Long userId, String deviceId) {
if (StringUtils.hasText(deviceId)) {
eventPublisher.publishEvent(
new AppInteractionMergeRequested(userId, deviceId.trim()));
}
}
private static final String REGISTER_IP_LIMIT_KEY = "app.register.max-per-ip-per-day";
private static final String REGISTER_DEVICE_LIMIT_KEY = "app.register.max-per-device-per-day";