fix(app): 修复 AppController 安全与查询问题
- 加强异常处理、类型安全和图片上传校验 - 优化设备相关查询,避免重复访问数据源 - 补充并记录并发测试与审查修复实施计划
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
package org.dromara.app.controller;
|
||||
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.hutool.core.io.FileTypeUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.lang.Validator;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.crypto.digest.BCrypt;
|
||||
import cn.hutool.json.JSONArray;
|
||||
@@ -13,10 +13,7 @@ import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.app.domain.bo.AppDeviceBo;
|
||||
import org.dromara.app.domain.bo.AppScheduleBo;
|
||||
import org.dromara.app.domain.bo.AppSchedulingDeviceBo;
|
||||
import org.dromara.app.domain.bo.AppWateringLogBo;
|
||||
import org.dromara.app.domain.bo.*;
|
||||
import org.dromara.app.domain.vo.*;
|
||||
import org.dromara.app.service.*;
|
||||
import org.dromara.common.core.domain.R;
|
||||
@@ -732,25 +729,12 @@ public class AppController extends BaseController {
|
||||
/**
|
||||
* app用户手机号/邮箱找回忘记密码
|
||||
*/
|
||||
@SaIgnore
|
||||
@ApiEncrypt
|
||||
@PostMapping("/retrievePassword")
|
||||
public R<Void> forgot(@RequestBody String body) {
|
||||
SysUserBo bo = JsonUtils.parseObject(body, SysUserBo.class);
|
||||
bo.setUserId(LoginHelper.getUserId());
|
||||
|
||||
if(Validator.isEmail(bo.getUserName())){
|
||||
boolean checkPhoneFlag = userService.checkEmailUnique(bo);
|
||||
if (!checkPhoneFlag){
|
||||
throw new UserException("user.email.not.username");
|
||||
}
|
||||
}else if (Validator.isMobile(bo.getUserName())){
|
||||
boolean checkPhoneFlag = userService.checkPhoneUnique(bo);
|
||||
if (!checkPhoneFlag){
|
||||
throw new UserException("user.mobile.phone.number.not.username");
|
||||
}
|
||||
}
|
||||
|
||||
return toAjax(userService.updateUserPas(bo));
|
||||
public R<Void> forgot(@Validated @RequestBody AppForgotPasswordBo request) {
|
||||
return toAjax(userService.resetPasswordByVerificationCode(
|
||||
request.getUsername(), request.getCode(), request.getPassword()));
|
||||
}
|
||||
|
||||
private String formatSecondTime(Date time) {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.dromara.app.domain.bo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAlias;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
/**
|
||||
* APP 忘记密码请求。
|
||||
*/
|
||||
@Data
|
||||
public class AppForgotPasswordBo {
|
||||
|
||||
@JsonAlias("userName")
|
||||
@NotBlank(message = "账号不能为空")
|
||||
@Length(min = 2, max = 64, message = "账号长度必须在2到64个字符之间")
|
||||
private String username;
|
||||
|
||||
@JsonAlias("smsCode")
|
||||
@NotBlank(message = "验证码不能为空")
|
||||
private String code;
|
||||
|
||||
@NotBlank(message = "新密码不能为空")
|
||||
@Length(min = 5, max = 30, message = "密码长度必须在5到30个字符之间")
|
||||
private String password;
|
||||
}
|
||||
@@ -19,6 +19,7 @@ public class DeviceCommand implements Serializable {
|
||||
private String commandType;
|
||||
private String topic;
|
||||
private Map<String, Object> payload = new HashMap<>();
|
||||
private Boolean retryEnabled = Boolean.TRUE;
|
||||
private int retryCount;
|
||||
private long createdAt;
|
||||
private long lastSentAt;
|
||||
|
||||
@@ -123,6 +123,7 @@ DeviceRegisterHandler implements MqttTopicHandler {
|
||||
command.setDeviceMac(deviceMac);
|
||||
command.setCommandType("registerDeviceNo");
|
||||
command.setTopic("/" + deviceMac.trim().toLowerCase(Locale.ROOT) + "/subscriber/cmd");
|
||||
command.setRetryEnabled(false);
|
||||
command.getPayload().put("deviceNo", deviceNo);
|
||||
command.getPayload().put("deviceMac", deviceMac);
|
||||
|
||||
|
||||
@@ -3,10 +3,7 @@ package org.dromara.app.controller;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.dromara.app.domain.bo.AppDeviceBo;
|
||||
import org.dromara.app.domain.bo.AppScheduleBo;
|
||||
import org.dromara.app.domain.bo.AppSchedulingDeviceBo;
|
||||
import org.dromara.app.domain.bo.AppWateringLogBo;
|
||||
import org.dromara.app.domain.bo.*;
|
||||
import org.dromara.app.domain.vo.*;
|
||||
import org.dromara.app.service.*;
|
||||
import org.dromara.common.core.domain.R;
|
||||
@@ -129,6 +126,41 @@ public class AppControllerTest {
|
||||
.hasMessage("版本配置不存在");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retrievePassword_resetsPasswordWithoutReadingLoginState() {
|
||||
AppController controller = newController();
|
||||
AppForgotPasswordBo request = new AppForgotPasswordBo();
|
||||
request.setUsername("alice@example.com");
|
||||
request.setCode("123456");
|
||||
request.setPassword("newPassword");
|
||||
when(userService.resetPasswordByVerificationCode("alice@example.com", "123456", "newPassword"))
|
||||
.thenReturn(true);
|
||||
|
||||
try (MockedStatic<LoginHelper> loginHelper = mockStatic(LoginHelper.class)) {
|
||||
R<Void> result = controller.forgot(request);
|
||||
|
||||
assertThat(result.getCode()).as(result.getMsg()).isEqualTo(200);
|
||||
loginHelper.verifyNoInteractions();
|
||||
}
|
||||
verify(userService).resetPasswordByVerificationCode(
|
||||
"alice@example.com", "123456", "newPassword");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retrievePassword_acceptsLegacyRequestFieldAliases() throws Exception {
|
||||
AppController controller = newController();
|
||||
AppForgotPasswordBo request = new ObjectMapper().readValue(
|
||||
"{\"userName\":\"13305376054\",\"smsCode\":\"654321\",\"password\":\"newPassword\"}",
|
||||
AppForgotPasswordBo.class);
|
||||
when(userService.resetPasswordByVerificationCode("13305376054", "654321", "newPassword"))
|
||||
.thenReturn(true);
|
||||
|
||||
R<Void> result = controller.forgot(request);
|
||||
|
||||
assertThat(result.getCode()).as(result.getMsg()).isEqualTo(200);
|
||||
verify(userService).resetPasswordByVerificationCode("13305376054", "654321", "newPassword");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uploadImage_uploadsToOssAndReturnsBackendVisibleInfo() {
|
||||
AppController controller = newController();
|
||||
|
||||
@@ -59,6 +59,7 @@ class DeviceRegisterHandlerTest {
|
||||
assertThat(captor.getValue().getTopic()).isEqualTo("/aa:bb:cc/subscriber/cmd");
|
||||
assertThat(captor.getValue().getCommandType()).isEqualTo("registerDeviceNo");
|
||||
assertThat(captor.getValue().getDeviceNo()).isEqualTo("D01");
|
||||
assertThat(captor.getValue().getRetryEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user