From 4f367056ab0e73d044e920d44b1d7dd0c8b65d80 Mon Sep 17 00:00:00 2001
From: “mitao” <“2763622819@qq.com”>
Date: 星期二, 12 五月 2026 14:25:28 +0800
Subject: [PATCH] fix:注册流程优化、屏蔽账号密码登录、已登录后token永不过期

---
 tcm-training-admin-backend/src/test/java/com/tcm/training/admin/app/auth/service/AppAuthServiceTest.java |  160 +++++++++++++++++++----------------------------------
 1 files changed, 58 insertions(+), 102 deletions(-)

diff --git a/tcm-training-admin-backend/src/test/java/com/tcm/training/admin/app/auth/service/AppAuthServiceTest.java b/tcm-training-admin-backend/src/test/java/com/tcm/training/admin/app/auth/service/AppAuthServiceTest.java
index 41dd1a6..00e455e 100644
--- a/tcm-training-admin-backend/src/test/java/com/tcm/training/admin/app/auth/service/AppAuthServiceTest.java
+++ b/tcm-training-admin-backend/src/test/java/com/tcm/training/admin/app/auth/service/AppAuthServiceTest.java
@@ -10,8 +10,6 @@
 import com.tcm.training.admin.app.auth.dto.AppWechatLoginRequest;
 import com.tcm.training.admin.app.auth.vo.AppLoginResponse;
 import com.tcm.training.admin.app.auth.vo.AppPasswordResetVerifyResponse;
-import com.tcm.training.admin.app.auth.vo.AppSmsCodeSendResponse;
-import com.tcm.training.admin.app.auth.exception.InviteCodeRequiredException;
 import com.tcm.training.admin.app.share.service.AppShareService;
 import com.tcm.training.admin.member.entity.AppUser;
 import com.tcm.training.admin.member.mapper.UserMapper;
@@ -26,13 +24,9 @@
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 import org.springframework.data.redis.core.StringRedisTemplate;
-import org.springframework.data.redis.core.ValueOperations;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 
-import java.util.concurrent.TimeUnit;
-
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.mockito.ArgumentMatchers.any;
@@ -79,9 +73,6 @@
     @Mock
     private StringRedisTemplate stringRedisTemplate;
 
-    @Mock
-    private ValueOperations<String, String> valueOperations;
-
     private AppAuthService appAuthService;
 
     @Captor
@@ -105,128 +96,69 @@
     }
 
     /**
-     * 密码登录成功时应返回统一登录响应并建立 APP 登录态。
+     * 密码登录能力下线后旧客户端调用应返回统一提示。
      */
     @Test
-    void passwordLoginShouldReturnTokenWhenPasswordMatches() {
+    void passwordLoginShouldReturnDisabledMessage() {
         AppPasswordLoginRequest request = new AppPasswordLoginRequest();
         request.setPhone("13800138000");
         request.setPassword("abc123!!");
 
-        AppUser user = buildEnabledUser("13800138000", "ENCODED");
-        SaTokenInfo tokenInfo = new SaTokenInfo();
-        tokenInfo.setTokenValue("token-value");
-        tokenInfo.setTokenTimeout(7200L);
-
-        when(userMapper.selectOne(any())).thenReturn(user);
-        when(passwordEncoder.matches("abc123!!", "ENCODED")).thenReturn(true);
-        when(appAuthSessionService.getTokenInfo()).thenReturn(tokenInfo);
-
-        AppLoginResponse response = appAuthService.passwordLogin(request);
-
-        verify(appAuthSessionService).login(1L);
-        assertEquals("token-value", response.getToken());
-        assertEquals("Bearer", response.getTokenType());
-        assertEquals(7200L, response.getExpiresIn());
-        assertEquals(Long.valueOf(1L), response.getUser().getId());
-        assertEquals("13800138000", response.getUser().getPhone());
-    }
-
-    /**
-     * 密码错误时应返回统一错误文案。
-     */
-    @Test
-    void passwordLoginShouldFailWhenPasswordMismatch() {
-        AppPasswordLoginRequest request = new AppPasswordLoginRequest();
-        request.setPhone("13800138000");
-        request.setPassword("bad-password");
-
-        AppUser user = buildEnabledUser("13800138000", "ENCODED");
-        when(userMapper.selectOne(any())).thenReturn(user);
-        when(passwordEncoder.matches("bad-password", "ENCODED")).thenReturn(false);
-
         IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
                 () -> appAuthService.passwordLogin(request));
 
-        assertEquals("账号或密码错误", exception.getMessage());
+        assertEquals("当前版本仅支持验证码登录", exception.getMessage());
+        verify(passwordEncoder, never()).matches(anyString(), anyString());
+        verify(appAuthSessionService, never()).login(anyLong());
     }
 
     /**
-     * 忘记密码发码仅允许已启用用户发送。
+     * 忘记密码发码能力下线后旧客户端调用应返回统一提示。
      */
     @Test
-    void sendPasswordResetCodeShouldReturnExpireSeconds() {
+    void sendPasswordResetCodeShouldReturnDisabledMessage() {
         AppSmsCodeSendRequest request = new AppSmsCodeSendRequest();
         request.setPhone("13800138001");
 
-        when(userMapper.selectOne(any())).thenReturn(buildEnabledUser("13800138001", "ENCODED"));
-        when(appSmsCodeService.createPasswordResetCode("13800138001")).thenReturn(new AppSmsCodeSendResponse(300));
+        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
+                () -> appAuthService.sendPasswordResetCode(request));
 
-        AppSmsCodeSendResponse response = appAuthService.sendPasswordResetCode(request);
-
-        assertEquals(300, response.getExpireInSeconds());
+        assertEquals("当前版本仅支持验证码登录", exception.getMessage());
+        verify(appSmsCodeService, never()).createPasswordResetCode(anyString());
     }
 
     /**
-     * 忘记密码验证码校验成功后应签发一次性重置凭证并写入缓存。
+     * 忘记密码验证码校验能力下线后旧客户端调用应返回统一提示。
      */
     @Test
-    void verifyPasswordResetCodeShouldCacheTicket() {
+    void verifyPasswordResetCodeShouldReturnDisabledMessage() {
         AppPasswordResetVerifyRequest request = new AppPasswordResetVerifyRequest();
         request.setPhone("13800138002");
         request.setCode("666666");
 
-        when(userMapper.selectOne(any())).thenReturn(buildEnabledUser("13800138002", "ENCODED"));
-        when(stringRedisTemplate.opsForValue()).thenReturn(valueOperations);
-        doNothing().when(appSmsCodeService).validatePasswordResetCode("13800138002", "666666");
+        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
+                () -> appAuthService.verifyPasswordResetCode(request));
 
-        AppPasswordResetVerifyResponse response = appAuthService.verifyPasswordResetCode(request);
-
-        assertNotNull(response.getResetTicket());
-        verify(valueOperations).set(anyString(), anyString(), anyLong(), any(TimeUnit.class));
+        assertEquals("当前版本仅支持验证码登录", exception.getMessage());
+        verify(appSmsCodeService, never()).validatePasswordResetCode(anyString(), anyString());
     }
 
     /**
-     * 使用有效重置凭证时应更新数据库中的密码并销毁凭证。
+     * 重置密码能力下线后旧客户端调用应返回统一提示。
      */
     @Test
-    void resetPasswordShouldUpdatePasswordAndDeleteTicket() {
+    void resetPasswordShouldReturnDisabledMessage() {
         AppPasswordResetRequest request = new AppPasswordResetRequest();
         request.setResetTicket("ticket-1");
         request.setPassword("abc123!!");
         request.setConfirmPassword("abc123!!");
 
-        AppUser user = buildEnabledUser("13800138003", "OLD");
-
-        when(stringRedisTemplate.opsForValue()).thenReturn(valueOperations);
-        when(valueOperations.get(anyString())).thenReturn("13800138003");
-        when(userMapper.selectOne(any())).thenReturn(user);
-        when(passwordEncoder.encode("abc123!!")).thenReturn("NEW-ENCODED");
-
-        appAuthService.resetPassword(request);
-
-        verify(userMapper).updateById(appUserCaptor.capture());
-        verify(stringRedisTemplate).delete(anyString());
-        assertEquals("NEW-ENCODED", appUserCaptor.getValue().getPassword());
-    }
-
-    /**
-     * 重置凭证失效时应拒绝更新密码。
-     */
-    @Test
-    void resetPasswordShouldFailWhenTicketExpired() {
-        AppPasswordResetRequest request = new AppPasswordResetRequest();
-        request.setResetTicket("expired-ticket");
-        request.setPassword("abc123!!");
-        request.setConfirmPassword("abc123!!");
-
-        when(stringRedisTemplate.opsForValue()).thenReturn(valueOperations);
-        when(valueOperations.get(anyString())).thenReturn(null);
-
         IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
                 () -> appAuthService.resetPassword(request));
 
-        assertEquals("重置凭证已失效,请重新验证", exception.getMessage());
+        assertEquals("当前版本仅支持验证码登录", exception.getMessage());
+        verify(passwordEncoder, never()).encode(anyString());
+        verify(userMapper, never()).updateById(any(AppUser.class));
     }
 
     /**
@@ -310,10 +242,10 @@
     }
 
     /**
-     * 微信首次登录未携带邀请码时应提示联系管理员获取。
+     * 微信首次登录未携带邀请码时应创建待绑定手机号的临时用户。
      */
     @Test
-    void wechatLoginShouldRequireInviteCodeWhenOpenidNotExists() {
+    void wechatLoginShouldCreatePendingUserWhenInviteCodeMissing() {
         AppWechatLoginRequest request = new AppWechatLoginRequest();
         request.setAccessToken("access-token");
         request.setOpenid("openid-new");
@@ -323,12 +255,19 @@
 
         when(appWechatAuthClient.resolveUserProfile(request)).thenReturn(profile);
         when(userMapper.selectOne(any())).thenReturn(null);
+        when(userMapper.insert(any(AppUser.class))).thenAnswer(invocation -> {
+            AppUser inserted = invocation.getArgument(0);
+            inserted.setId(2001L);
+            return 1;
+        });
+        when(appAuthSessionService.getTokenInfo()).thenReturn(buildTokenInfo("wechat-pending-token", 7200L));
 
-        InviteCodeRequiredException exception = assertThrows(InviteCodeRequiredException.class,
-                () -> appAuthService.wechatLogin(request));
+        AppLoginResponse response = appAuthService.wechatLogin(request);
 
-        assertEquals("暂无邀请码,请联系管理员获取", exception.getMessage());
-        verify(userMapper, never()).insert(any());
+        verify(userMapper).insert(appUserCaptor.capture());
+        assertNull(appUserCaptor.getValue().getPhone());
+        assertEquals("openid-new", appUserCaptor.getValue().getWechatOpenid());
+        assertEquals("wechat-pending-token", response.getToken());
     }
 
     /**
@@ -405,10 +344,10 @@
     }
 
     /**
-     * 苹果首次登录未携带邀请码时应提示联系管理员获取。
+     * 苹果首次登录未携带邀请码时应创建待绑定手机号的临时用户。
      */
     @Test
-    void appleLoginShouldRequireInviteCodeWhenSubjectNotExists() {
+    void appleLoginShouldCreatePendingUserWhenInviteCodeMissing() {
         AppAppleLoginRequest request = new AppAppleLoginRequest();
         request.setIdentityToken("identity-token");
         request.setUserIdentifier("apple-user-new");
@@ -419,12 +358,19 @@
 
         when(appAppleAuthClient.resolveUserProfile(request)).thenReturn(profile);
         when(userMapper.selectOne(any())).thenReturn(null);
+        when(userMapper.insert(any(AppUser.class))).thenAnswer(invocation -> {
+            AppUser inserted = invocation.getArgument(0);
+            inserted.setId(3001L);
+            return 1;
+        });
+        when(appAuthSessionService.getTokenInfo()).thenReturn(buildTokenInfo("apple-pending-token", 7200L));
 
-        InviteCodeRequiredException exception = assertThrows(InviteCodeRequiredException.class,
-                () -> appAuthService.appleLogin(request));
+        AppLoginResponse response = appAuthService.appleLogin(request);
 
-        assertEquals("暂无邀请码,请联系管理员获取", exception.getMessage());
-        verify(userMapper, never()).insert(any());
+        verify(userMapper).insert(appUserCaptor.capture());
+        assertNull(appUserCaptor.getValue().getPhone());
+        assertEquals("apple-subject-new", appUserCaptor.getValue().getAppleIdentitySubject());
+        assertEquals("apple-pending-token", response.getToken());
     }
 
     /**
@@ -456,6 +402,16 @@
     }
 
     /**
+     * 构造测试用 token 信息。
+     */
+    private SaTokenInfo buildTokenInfo(String tokenValue, long timeout) {
+        SaTokenInfo tokenInfo = new SaTokenInfo();
+        tokenInfo.setTokenValue(tokenValue);
+        tokenInfo.setTokenTimeout(timeout);
+        return tokenInfo;
+    }
+
+    /**
      * 统一构造启用中的 APP 用户测试桩。
      */
     private AppUser buildEnabledUser(String phone, String password) {

--
Gitblit v1.7.1