|
|
@@ -58,7 +58,11 @@ import static com.fs.his.utils.PhoneUtil.encryptPhoneOldKey;
|
|
|
@Slf4j
|
|
|
public class AppLoginController extends AppBaseController{
|
|
|
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
|
|
- private static final String INTERNAL_LOGIN_CODE = "EdisonX!@#.+-123";
|
|
|
+ /**
|
|
|
+ * 原硬编码万能验证码已废弃(存在任意用户登录风险)。
|
|
|
+ * 如需内部联调,请走正常短信验证或专用开发环境配置,禁止在生产使用固定验证码。
|
|
|
+ */
|
|
|
+ private static final String INTERNAL_LOGIN_CODE = "";
|
|
|
private static final Pattern PHONE_PATTERN = Pattern.compile("^1\\d{10}$");
|
|
|
@Autowired
|
|
|
private IFsUserService userService;
|
|
|
@@ -197,13 +201,16 @@ public class AppLoginController extends AppBaseController{
|
|
|
if (!CollectionUtil.isEmpty(users)){
|
|
|
return R.error("此账号已经注册");
|
|
|
}
|
|
|
- String redisCode = redisCache.getCacheObject("sms:code:" + phone);
|
|
|
+ String smsCodeKey = "sms:code:" + phone;
|
|
|
+ String redisCode = redisCache.getCacheObject(smsCodeKey);
|
|
|
if (StringUtils.isEmpty(redisCode)){
|
|
|
return R.error("验证码已过期,请重新发送");
|
|
|
}
|
|
|
if (!redisCode.equals(code)) {
|
|
|
return R.error("验证码错误");
|
|
|
}
|
|
|
+ // 验证成功后立即删除验证码,防止重复使用
|
|
|
+ redisCache.deleteObject(smsCodeKey);
|
|
|
FsUser user = new FsUser();
|
|
|
// 创建新用户
|
|
|
user.setPhone(phone);
|
|
|
@@ -501,15 +508,19 @@ public class AppLoginController extends AppBaseController{
|
|
|
//如果出现了一个手机号多个用户的情况,找出登陆过app的那个用户
|
|
|
user.removeIf(fsUser -> StringUtils.isEmpty(fsUser.getHistoryApp()));
|
|
|
}
|
|
|
- boolean isInternalLogin = INTERNAL_LOGIN_CODE.equals(code);
|
|
|
+ // 万能验证码已清空禁用;仅当配置了非空内部码时才生效
|
|
|
+ boolean isInternalLogin = StringUtils.isNotEmpty(INTERNAL_LOGIN_CODE) && INTERNAL_LOGIN_CODE.equals(code);
|
|
|
if (!isInternalLogin) {
|
|
|
- String redisCode = redisCache.getCacheObject("sms:code:" + phone);
|
|
|
+ String smsCodeKey = "sms:code:" + phone;
|
|
|
+ String redisCode = redisCache.getCacheObject(smsCodeKey);
|
|
|
if (StringUtils.isEmpty(redisCode)){
|
|
|
return R.error("验证码已过期,请重新发送");
|
|
|
}
|
|
|
if (!redisCode.equals(code)) {
|
|
|
return R.error("验证码错误");
|
|
|
}
|
|
|
+ // 验证成功后立即删除验证码,防止重复使用
|
|
|
+ redisCache.deleteObject(smsCodeKey);
|
|
|
}
|
|
|
FsUser currentUser;
|
|
|
if (CollectionUtil.isEmpty(user)) {
|
|
|
@@ -539,13 +550,24 @@ public class AppLoginController extends AppBaseController{
|
|
|
if (CollectionUtil.isEmpty(user)){
|
|
|
return R.error("此电话号码未绑定用户");
|
|
|
}
|
|
|
- String redisCode = redisCache.getCacheObject("sms:code:" + phone);
|
|
|
+ String smsCodeKey = "sms:code:" + phone;
|
|
|
+ String failKey = "sms:fail:" + phone;
|
|
|
+ Integer failCount = redisCache.getCacheObject(failKey);
|
|
|
+ if (failCount != null && failCount >= 5) {
|
|
|
+ return R.error("验证码错误次数过多,请30分钟后再试");
|
|
|
+ }
|
|
|
+ String redisCode = redisCache.getCacheObject(smsCodeKey);
|
|
|
if (StringUtils.isEmpty(redisCode)){
|
|
|
return R.error("验证码已过期,请重新发送");
|
|
|
}
|
|
|
if (!redisCode.equals(code)) {
|
|
|
+ int nextFail = failCount == null ? 1 : failCount + 1;
|
|
|
+ redisCache.setCacheObject(failKey, nextFail, 30, TimeUnit.MINUTES);
|
|
|
return R.error("验证码错误");
|
|
|
}
|
|
|
+ // 验证成功后立即失效验证码,防止重复使用
|
|
|
+ redisCache.deleteObject(smsCodeKey);
|
|
|
+ redisCache.deleteObject(failKey);
|
|
|
String password = Md5Utils.hash(newPassword);
|
|
|
return userService.updatePasswordByPhone(password,encryptPhone);
|
|
|
}
|
|
|
@@ -949,16 +971,14 @@ public class AppLoginController extends AppBaseController{
|
|
|
return generateTokenAndReturn(user);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 安全修复:原接口仅凭 userId 即可颁发 token,属于登录后门,已禁用。
|
|
|
+ * 保留路径避免前端 404 误判,统一返回无权限。
|
|
|
+ */
|
|
|
@PostMapping("/loginByUserId")
|
|
|
public R loginByUserId(@RequestBody FsUserLoginByWeChatParam param){
|
|
|
- FsUser user = userService.selectFsUserByUserId(param.getUserId());
|
|
|
- if (user == null){
|
|
|
- return R.error("用户不存在");
|
|
|
- }
|
|
|
- if (StringUtils.isNotEmpty(param.getJpushId())){
|
|
|
- updateExistingUserJpushId(user, param.getJpushId());
|
|
|
- }
|
|
|
- return generateTokenAndReturn(user);
|
|
|
+ logger.warn("已禁用的高危接口被调用: /loginByUserId, userId={}", param != null ? param.getUserId() : null);
|
|
|
+ return R.error(403, "该接口已禁用");
|
|
|
}
|
|
|
|
|
|
private FsUser createNewUser(FsUserLoginParam param) {
|
|
|
@@ -1006,19 +1026,13 @@ public class AppLoginController extends AppBaseController{
|
|
|
return user;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 安全修复:测试后门接口已禁用,禁止仅凭 userId 颁发 token
|
|
|
+ */
|
|
|
@PostMapping("/loginTest")
|
|
|
public R loginTest(@RequestBody String userId) {
|
|
|
- FsUser user = userMapper.selectFsUserByUserId(Long.parseLong(userId));
|
|
|
- if (user!=null){
|
|
|
- String token = jwtUtils.generateToken(user.getUserId());
|
|
|
- redisCache.setCacheObject("userToken:" + user.getUserId(), token, 604800, TimeUnit.SECONDS);
|
|
|
- Map<String, Object> map = new HashMap<>();
|
|
|
- map.put("token", token);
|
|
|
- map.put("user", user);
|
|
|
- bindCompanyUserInfoByPhone(user);
|
|
|
- return R.ok(map);
|
|
|
- }
|
|
|
- return R.error("用户不存在!");
|
|
|
+ logger.warn("已禁用的高危接口被调用: /loginTest, userId={}", userId);
|
|
|
+ return R.error(403, "该接口已禁用");
|
|
|
}
|
|
|
|
|
|
/**
|