|
@@ -2,6 +2,7 @@ package com.backendsys.modules.system.service.impl;
|
|
|
|
|
|
import cn.hutool.core.date.DateUtil;
|
|
import cn.hutool.core.date.DateUtil;
|
|
import cn.hutool.json.JSONUtil;
|
|
import cn.hutool.json.JSONUtil;
|
|
|
|
+import com.backendsys.config.Kaptcha.KaptchaUtil;
|
|
import com.backendsys.exception.CustException;
|
|
import com.backendsys.exception.CustException;
|
|
import com.backendsys.modules.common.config.redis.utils.RedisUtil;
|
|
import com.backendsys.modules.common.config.redis.utils.RedisUtil;
|
|
import com.backendsys.modules.common.config.security.entity.SecurityUserInfo;
|
|
import com.backendsys.modules.common.config.security.entity.SecurityUserInfo;
|
|
@@ -30,20 +31,17 @@ import javax.imageio.ImageIO;
|
|
import java.awt.image.BufferedImage;
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
-import java.util.Date;
|
|
|
|
-import java.util.List;
|
|
|
|
-import java.util.Map;
|
|
|
|
-import java.util.UUID;
|
|
|
|
|
|
+import java.util.*;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
@Service
|
|
@Service
|
|
public class SysAuthV2ServiceImpl implements SysAuthV2Service {
|
|
public class SysAuthV2ServiceImpl implements SysAuthV2Service {
|
|
|
|
|
|
- @Autowired
|
|
|
|
- private RedisUtil redisUtil;
|
|
|
|
@Autowired
|
|
@Autowired
|
|
private JwtUtil jwtUtil;
|
|
private JwtUtil jwtUtil;
|
|
@Autowired
|
|
@Autowired
|
|
|
|
+ private RedisUtil redisUtil;
|
|
|
|
+ @Autowired
|
|
private HttpRequestUtil httpRequestUtil;
|
|
private HttpRequestUtil httpRequestUtil;
|
|
@Autowired
|
|
@Autowired
|
|
private CountUtilV2 countUtilV2;
|
|
private CountUtilV2 countUtilV2;
|
|
@@ -68,6 +66,13 @@ public class SysAuthV2ServiceImpl implements SysAuthV2Service {
|
|
@Value("${TOKEN_DURATION_SYSTEM}")
|
|
@Value("${TOKEN_DURATION_SYSTEM}")
|
|
private Integer TOKEN_DURATION_SYSTEM;
|
|
private Integer TOKEN_DURATION_SYSTEM;
|
|
|
|
|
|
|
|
+ @Value("${spring.application.name}")
|
|
|
|
+ private String APPLICATION_NAME;
|
|
|
|
+ private String redisKeyOfLogin = APPLICATION_NAME + "-sms-login";
|
|
|
|
+ private String redisKeyOfRegister = APPLICATION_NAME + "-sms-register";
|
|
|
|
+ private String redisKeyOfLoginFail = APPLICATION_NAME + "-login-error";
|
|
|
|
+ private String redisKeyOfRegisterFail = APPLICATION_NAME + "-register-error";
|
|
|
|
+
|
|
@Override
|
|
@Override
|
|
public void renderCaptcha(HttpServletResponse response) throws IOException {
|
|
public void renderCaptcha(HttpServletResponse response) throws IOException {
|
|
byte[] captchaChallengeAsJpeg;
|
|
byte[] captchaChallengeAsJpeg;
|
|
@@ -103,9 +108,10 @@ public class SysAuthV2ServiceImpl implements SysAuthV2Service {
|
|
|
|
|
|
// [方法] 登录失败 (errMsg: 错误提示文本, username: 用户名, intercept: 是否拦截)
|
|
// [方法] 登录失败 (errMsg: 错误提示文本, username: 用户名, intercept: 是否拦截)
|
|
private void loginFail(String errMsg, String username, Boolean isIntercept) {
|
|
private void loginFail(String errMsg, String username, Boolean isIntercept) {
|
|
|
|
+ // 删除图形验证码
|
|
redisUtil.delete(httpRequestUtil.getKaptchaKey());
|
|
redisUtil.delete(httpRequestUtil.getKaptchaKey());
|
|
// 添加登录错误的冻结标记
|
|
// 添加登录错误的冻结标记
|
|
- if (isIntercept) countUtilV2.setErrorCount("login-error", username);
|
|
|
|
|
|
+ if (isIntercept) countUtilV2.setErrorCount(redisKeyOfLoginFail, username);
|
|
throw new CustException(errMsg, ResultEnum.INVALID_CREDENTIALS.getCode());
|
|
throw new CustException(errMsg, ResultEnum.INVALID_CREDENTIALS.getCode());
|
|
}
|
|
}
|
|
|
|
|
|
@@ -116,7 +122,7 @@ public class SysAuthV2ServiceImpl implements SysAuthV2Service {
|
|
SysUserInfo sysUserInfo = sysUserV2Service.selectUserInfo(user_id);
|
|
SysUserInfo sysUserInfo = sysUserV2Service.selectUserInfo(user_id);
|
|
|
|
|
|
// 清除缓存
|
|
// 清除缓存
|
|
- redisUtil.delete(httpRequestUtil.getKaptchaKey()); // 作废验证码密钥
|
|
|
|
|
|
+ redisUtil.delete(httpRequestUtil.getKaptchaKey()); // 删除图形验证码
|
|
redisUtil.delete("token:id:" + sysUserInfo.getLast_login_uuid()); // 删除旧的登录缓存 (Redis)
|
|
redisUtil.delete("token:id:" + sysUserInfo.getLast_login_uuid()); // 删除旧的登录缓存 (Redis)
|
|
|
|
|
|
// 判断用户是否审核
|
|
// 判断用户是否审核
|
|
@@ -154,6 +160,9 @@ public class SysAuthV2ServiceImpl implements SysAuthV2Service {
|
|
return sysUserInfo;
|
|
return sysUserInfo;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 登录 (用户名)
|
|
|
|
+ */
|
|
@Override
|
|
@Override
|
|
@Transactional
|
|
@Transactional
|
|
public SysUserInfo login(SysAuth sysAuth) {
|
|
public SysUserInfo login(SysAuth sysAuth) {
|
|
@@ -163,17 +172,17 @@ public class SysAuthV2ServiceImpl implements SysAuthV2Service {
|
|
String captcha = sysAuth.getCaptcha();
|
|
String captcha = sysAuth.getCaptcha();
|
|
|
|
|
|
// 判断是否处于登录错误的冻结状态 (2分钟内错误5次,则出现冻结提示)
|
|
// 判断是否处于登录错误的冻结状态 (2分钟内错误5次,则出现冻结提示)
|
|
- countUtilV2.checkErrorStatus("login-error", username);
|
|
|
|
|
|
+ countUtilV2.checkErrorStatus(redisKeyOfLoginFail, username);
|
|
|
|
|
|
- // [Method] 判断验证码是否正确 (RedisKey: (ua + ip))
|
|
|
|
|
|
+ // 判断图形验证码是否正确
|
|
if (!captchaUtil.isCaptchaValid(captcha, httpRequestUtil.getKaptchaKey())) {
|
|
if (!captchaUtil.isCaptchaValid(captcha, httpRequestUtil.getKaptchaKey())) {
|
|
loginFail("验证码错误", username, false);
|
|
loginFail("验证码错误", username, false);
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
// [Method] 判断 用户 是否存在 && 密码是否正确
|
|
// [Method] 判断 用户 是否存在 && 密码是否正确
|
|
- SysUser sysUserSimple = sysUserDao.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username));
|
|
|
|
- if (sysUserSimple == null) {
|
|
|
|
|
|
+ SysUser sysUser = sysUserDao.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username));
|
|
|
|
+ if (sysUser == null) {
|
|
// [登录失败] 用户不存在
|
|
// [登录失败] 用户不存在
|
|
loginFail("用户名或密码错误", username, true);
|
|
loginFail("用户名或密码错误", username, true);
|
|
return null;
|
|
return null;
|
|
@@ -181,16 +190,86 @@ public class SysAuthV2ServiceImpl implements SysAuthV2Service {
|
|
|
|
|
|
// [登录失败] 密码不正确
|
|
// [登录失败] 密码不正确
|
|
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
|
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
|
- if (!encoder.matches(password, sysUserSimple.getPassword())) {
|
|
|
|
|
|
+ if (!encoder.matches(password, sysUser.getPassword())) {
|
|
loginFail("用户名或密码错误", username, true);
|
|
loginFail("用户名或密码错误", username, true);
|
|
}
|
|
}
|
|
|
|
|
|
// [登录成功]
|
|
// [登录成功]
|
|
- return loginSuccess(sysUserSimple.getId(), sysAuth.getIs_remember());
|
|
|
|
|
|
+ return loginSuccess(sysUser.getId(), sysAuth.getIs_remember());
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @Override
|
|
|
|
+ @Transactional
|
|
|
|
+ public Map<String, Object> register(SysUserDTO sysUserDTO) {
|
|
|
|
+
|
|
|
|
+ String username = sysUserDTO.getUsername();
|
|
|
|
+ String password = sysUserDTO.getPassword();
|
|
|
|
+ String captcha = sysUserDTO.getCaptcha();
|
|
|
|
+
|
|
|
|
+ String phone = sysUserDTO.getPhone();
|
|
|
|
+ Integer phoneAreaCode = sysUserDTO.getPhone_area_code();
|
|
|
|
+ Integer phoneValidCode = sysUserDTO.getPhone_valid_code();
|
|
|
|
+
|
|
|
|
+ // -- 参数校验 --------------------------------------------------------------
|
|
|
|
+
|
|
|
|
+ // 判断是否处于登录错误的冻结状态 (2分钟内错误5次,则出现冻结提示)
|
|
|
|
+ countUtilV2.checkErrorStatus(redisKeyOfRegisterFail, username);
|
|
|
|
+ countUtilV2.checkErrorStatus(redisKeyOfRegisterFail, phone);
|
|
|
|
+
|
|
|
|
+ // 判断图形验证码是否正确
|
|
|
|
+ if (!captchaUtil.isCaptchaValid(captcha, httpRequestUtil.getKaptchaKey())) {
|
|
|
|
+ loginFail("验证码错误", username, false);
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // [查询] 判断用户名是否存在
|
|
|
|
+ SysUser sysUser1 = sysUserDao.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username));
|
|
|
|
+ if (sysUser1 != null) throw new CustException("用户名 (" + username + ") 已被注册");
|
|
|
|
+
|
|
|
|
+ // 判断短信验证码是否正确
|
|
|
|
+ String redisKey = redisKeyOfLogin + "-" + phone;
|
|
|
|
+ Integer smsCode = redisUtil.getCacheObject(redisKey);
|
|
|
|
+ // 判断是否发送验证码
|
|
|
|
+ if ("false".equals(SMS_DEBUG) && smsCode == null) throw new CustException("请先发送验证码");
|
|
|
|
+ // 判断短信验证码是否错误
|
|
|
|
+ if ("false".equals(SMS_DEBUG) && !smsCode.equals(phoneValidCode)) loginFail("短信验证码错误", phone, true);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // [查询] 判断手机号是否存在
|
|
|
|
+ LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
|
+ queryWrapper.eq(SysUser::getPhone, phone).eq(SysUser::getPhone_area_code, phoneAreaCode);
|
|
|
|
+ SysUser sysUser2 = sysUserDao.selectOne(queryWrapper);
|
|
|
|
+ if (sysUser2 != null) throw new CustException("手机号码 (+" + phoneAreaCode + " " + phone + ") 已被注册");
|
|
|
|
+
|
|
|
|
+ // -- 通过校验 --------------------------------------------------------------
|
|
|
|
+
|
|
|
|
+ // 密码二次加密
|
|
|
|
+ BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
|
|
|
+ String encodedPassword = encoder.encode(password);
|
|
|
|
+ sysUserDTO.setPassword(encodedPassword);
|
|
|
|
+
|
|
|
|
+ // 注册
|
|
|
|
+ SysUserDTO registerEntity = new SysUserDTO();
|
|
|
|
+ registerEntity.setUsername(sysUserDTO.getUsername());
|
|
|
|
+ registerEntity.setPhone(sysUserDTO.getPhone());
|
|
|
|
+ registerEntity.setPhone_area_code(sysUserDTO.getPhone_area_code());
|
|
|
|
+ registerEntity.setPassword(sysUserDTO.getPassword());
|
|
|
|
+ // 注册时,默认使用 游客 2L 权限
|
|
|
|
+ registerEntity.setRole_id(Arrays.asList(2L));
|
|
|
|
+ registerEntity.setInvite_code(sysUserDTO.getInvite_code());
|
|
|
|
+ // 注册时,状态为禁用
|
|
|
|
+ registerEntity.setStatus(-1);
|
|
|
|
+
|
|
|
|
+ sysUserDao.insertUser(registerEntity);
|
|
|
|
+ return Map.of("user_id", registerEntity.getId());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 登录 (手机号码)
|
|
|
|
+ */
|
|
@Override
|
|
@Override
|
|
@Transactional
|
|
@Transactional
|
|
public SysUserInfo loginWithPhone(SysAuthPhone sysAuthPhone) {
|
|
public SysUserInfo loginWithPhone(SysAuthPhone sysAuthPhone) {
|
|
@@ -200,30 +279,29 @@ public class SysAuthV2ServiceImpl implements SysAuthV2Service {
|
|
Integer phoneValidCode = sysAuthPhone.getPhone_valid_code();
|
|
Integer phoneValidCode = sysAuthPhone.getPhone_valid_code();
|
|
|
|
|
|
// 判断是否处于登录错误的冻结状态 (2分钟内错误5次,则出现冻结提示)
|
|
// 判断是否处于登录错误的冻结状态 (2分钟内错误5次,则出现冻结提示)
|
|
- countUtilV2.checkErrorStatus("login-error", sysAuthPhone.getPhone());
|
|
|
|
|
|
+ countUtilV2.checkErrorStatus(redisKeyOfLoginFail, phone);
|
|
|
|
|
|
- // [Redis] 验证码缓存
|
|
|
|
- String redisKey = "sms-login-" + phone;
|
|
|
|
|
|
+ // 判断短信验证码是否正确
|
|
|
|
+ String redisKey = redisKeyOfLogin + "-" + phone;
|
|
Integer smsCode = redisUtil.getCacheObject(redisKey);
|
|
Integer smsCode = redisUtil.getCacheObject(redisKey);
|
|
-
|
|
|
|
// 判断是否发送验证码
|
|
// 判断是否发送验证码
|
|
- if ("false".equals(SMS_DEBUG) &&smsCode == null) throw new CustException("请先发送验证码");
|
|
|
|
|
|
+ if ("false".equals(SMS_DEBUG) && smsCode == null) throw new CustException("请先发送验证码");
|
|
// 判断短信验证码是否错误
|
|
// 判断短信验证码是否错误
|
|
if ("false".equals(SMS_DEBUG) && !smsCode.equals(phoneValidCode)) loginFail("短信验证码错误", phone, true);
|
|
if ("false".equals(SMS_DEBUG) && !smsCode.equals(phoneValidCode)) loginFail("短信验证码错误", phone, true);
|
|
|
|
|
|
- // [Method] 判断手机号是否存在
|
|
|
|
- SysUser sysUserSimple = sysUserDao.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhone, phone));
|
|
|
|
- if (sysUserSimple == null) {
|
|
|
|
- // [登录失败] 用户不存在
|
|
|
|
|
|
+ // 判断手机号是否存在
|
|
|
|
+ LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
|
+ queryWrapper.eq(SysUser::getPhone, phone).eq(SysUser::getPhone_area_code, phoneAreaCode);
|
|
|
|
+ SysUser sysUser = sysUserDao.selectOne(queryWrapper);
|
|
|
|
+ if (sysUser == null) {
|
|
|
|
+ // [登录失败] 用户不存在 (并不会销毁短信验证码)
|
|
loginFail("手机号码不存在", phone, true);
|
|
loginFail("手机号码不存在", phone, true);
|
|
return null;
|
|
return null;
|
|
} else {
|
|
} else {
|
|
-
|
|
|
|
- // 登录成功,销毁 smsCode
|
|
|
|
|
|
+ // 登录成功,销毁短信验证码
|
|
redisUtil.delete(redisKey);
|
|
redisUtil.delete(redisKey);
|
|
-
|
|
|
|
// [登录成功]
|
|
// [登录成功]
|
|
- return loginSuccess(sysUserSimple.getId(), sysAuthPhone.getIs_remember());
|
|
|
|
|
|
+ return loginSuccess(sysUser.getId(), sysAuthPhone.getIs_remember());
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|