feat: 支持展示并复制重置后的密码

- 账号重置接口返回本次使用的默认强密码

- 管理端新增紧凑结果弹窗与复制反馈

- 补充服务测试和中英文文案
This commit is contained in:
2026-07-30 14:17:44 +08:00
parent 766554bf63
commit 5f11219226
8 changed files with 253 additions and 8 deletions

View File

@@ -32,7 +32,14 @@ public interface SysAccountService extends IService<SysAccount> {
SysAccount getByUsername(String userKey);
void resetPassword(BigInteger accountId, BigInteger operatorId);
/**
* 将账号密码重置为系统默认强密码。
*
* @param accountId 账号 ID
* @param operatorId 操作人账号 ID
* @return 本次重置后使用的明文密码
*/
String resetPassword(BigInteger accountId, BigInteger operatorId);
SysAccountBatchActionResultVo removeBatchWithResult(Collection<BigInteger> ids);

View File

@@ -231,21 +231,30 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
return getOne(w);
}
/**
* 将账号密码重置为系统默认强密码。
*
* @param accountId 账号 ID
* @param operatorId 操作人账号 ID
* @return 本次重置后使用的明文密码
*/
@Override
public void resetPassword(BigInteger accountId, BigInteger operatorId) {
public String resetPassword(BigInteger accountId, BigInteger operatorId) {
SysAccount record = getById(accountId);
if (record == null) {
throw new BusinessException("用户不存在");
}
validateResetPasswordAllowed(record);
String plainPassword = accountSecurityProperties.getDefaultResetPassword();
SysAccount update = new SysAccount();
update.setId(accountId);
update.setPassword(BCrypt.hashpw(accountSecurityProperties.getDefaultResetPassword()));
update.setPassword(BCrypt.hashpw(plainPassword));
update.setPasswordResetRequired(true);
update.setModified(new Date());
update.setModifiedBy(operatorId);
updateById(update);
StpUtil.kickout(accountId);
return plainPassword;
}
@Override

View File

@@ -1,17 +1,26 @@
package tech.easyflow.system.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.mybatisflex.core.query.QueryWrapper;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.MockedStatic;
import tech.easyflow.common.constant.enums.EnumAccountType;
import tech.easyflow.system.config.AccountSecurityProperties;
import tech.easyflow.system.entity.SysAccount;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -51,4 +60,54 @@ public class SysAccountServiceImplTest {
assertEquals("3", displayNameMap.get(BigInteger.valueOf(3)));
verify(service, times(1)).list(any(QueryWrapper.class));
}
/**
* 验证重置密码返回实际明文,同时持久化对应密文并踢出旧登录态。
*
* @throws Exception 注入测试配置失败
*/
@Test
public void shouldReturnPlainPasswordAfterReset() throws Exception {
BigInteger accountId = BigInteger.valueOf(10);
BigInteger operatorId = BigInteger.valueOf(20);
String expectedPassword = "!Reset123";
SysAccountServiceImpl service = spy(new SysAccountServiceImpl());
AccountSecurityProperties properties = new AccountSecurityProperties();
properties.setDefaultResetPassword(expectedPassword);
properties.afterPropertiesSet();
setField(service, "accountSecurityProperties", properties);
SysAccount account = new SysAccount();
account.setId(accountId);
account.setAccountType(EnumAccountType.NORMAL.getCode());
doReturn(account).when(service).getById(accountId);
doReturn(true).when(service).updateById(any(SysAccount.class));
try (MockedStatic<StpUtil> stp = mockStatic(StpUtil.class)) {
String actualPassword = service.resetPassword(accountId, operatorId);
assertEquals(expectedPassword, actualPassword);
ArgumentCaptor<SysAccount> updateCaptor = ArgumentCaptor.forClass(SysAccount.class);
verify(service).updateById(updateCaptor.capture());
SysAccount update = updateCaptor.getValue();
assertTrue(BCrypt.checkpw(expectedPassword, update.getPassword()));
assertEquals(Boolean.TRUE, update.getPasswordResetRequired());
assertEquals(operatorId, update.getModifiedBy());
stp.verify(() -> StpUtil.kickout(accountId), times(1));
}
}
/**
* 设置测试对象的私有字段。
*
* @param target 目标对象
* @param fieldName 字段名
* @param value 字段值
* @throws Exception 字段不存在或不可访问
*/
private void setField(Object target, String fieldName, Object value) throws Exception {
Field field = SysAccountServiceImpl.class.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(target, value);
}
}