diff --git a/src/main/java/com/gxwebsoft/common/system/controller/MainController.java b/src/main/java/com/gxwebsoft/common/system/controller/MainController.java index 4843570..b0ab0e3 100644 --- a/src/main/java/com/gxwebsoft/common/system/controller/MainController.java +++ b/src/main/java/com/gxwebsoft/common/system/controller/MainController.java @@ -392,21 +392,43 @@ public class MainController extends BaseController { update.setAvatar(user.getAvatar()); update.setBgImage(user.getBgImage()); update.setSex(user.getSex()); - // 手机号变更:仅当提交短信验证码且校验通过时才更新,防止未经验证的手机号被绑定 + // 手机号变更:两步验证 + // 第一步:短信验证码发往原手机号(验证当前账户归属),校验通过才允许换绑 + // 第二步:向新手机号发送验证码(验证新号归属);账号原本无手机号时,第一步的码已发往新号,无需第二步 if (StrUtil.isNotBlank(user.getSmsCode())) { String newPhone = user.getPhone(); if (StrUtil.isBlank(newPhone) || !CommonUtil.isValidPhoneNumber(newPhone)) { return fail("手机号格式不正确", null); } - String key = "code:" + newPhone; - String cached = redisUtil.get(key); + User currentUser = userService.getById(getLoginUserId()); + String currentPhone = currentUser != null ? currentUser.getPhone() : null; + // 第一步:校验原手机号(或账号原本无手机号时的新号)验证码 + String verifyPhone = StrUtil.isNotBlank(currentPhone) ? currentPhone : newPhone; + String oldKey = "code:" + verifyPhone; + String cachedOld = redisUtil.get(oldKey); String devCode = redisUtil.get(CACHE_KEY_VERIFICATION_CODE_BY_DEV_SMS); - if (StrUtil.isBlank(cached) || (!cached.equals(user.getSmsCode()) && !user.getSmsCode().equals(devCode))) { + if (StrUtil.isBlank(cachedOld) || (!cachedOld.equals(user.getSmsCode()) && !user.getSmsCode().equals(devCode))) { return fail("短信验证码不正确", null); } + // 第二步:校验新手机号验证码(仅当账号原本已绑定手机号,才需要二次验证新号归属) + if (StrUtil.isNotBlank(currentPhone)) { + String newKey = "code:" + newPhone; + String cachedNew = redisUtil.get(newKey); + if (StrUtil.isBlank(cachedNew) + || (!cachedNew.equals(user.getSmsCodeNew()) && !user.getSmsCodeNew().equals(devCode))) { + return fail("新手机号验证码不正确", null); + } + redisUtil.delete(newKey); + cacheClient.delete(newPhone); + } + // 新手机号唯一性校验:不可被其他账号占用 + User existed = userService.getByPhone(newPhone); + if (existed != null && !existed.getUserId().equals(getLoginUserId())) { + return fail("该手机号已被其他账号绑定", null); + } update.setPhone(newPhone); - redisUtil.delete(key); - cacheClient.delete(newPhone); + redisUtil.delete(oldKey); + cacheClient.delete(verifyPhone); } // 邮箱变更:仅当提交邮箱验证码且校验通过时才更新,防止未经验证的邮箱被绑定 if (StrUtil.isNotBlank(user.getEmailCode())) { diff --git a/src/main/java/com/gxwebsoft/common/system/entity/User.java b/src/main/java/com/gxwebsoft/common/system/entity/User.java index 47dce0e..b679890 100644 --- a/src/main/java/com/gxwebsoft/common/system/entity/User.java +++ b/src/main/java/com/gxwebsoft/common/system/entity/User.java @@ -69,6 +69,10 @@ public class User implements UserDetails { @TableField(exist = false) private String smsCode; + @Schema(description = "新手机号短信验证码(非数据库字段,仅用于换绑手机号时二次验证新号归属)") + @TableField(exist = false) + private String smsCodeNew; + @Schema(description = "资质") private String aptitude;