AppAuthServiceImpl.java 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. package com.backendsys.modules.app.service.impl;
  2. import cn.hutool.core.convert.Convert;
  3. import cn.hutool.core.date.DateUnit;
  4. import cn.hutool.core.date.DateUtil;
  5. import cn.hutool.json.JSONUtil;
  6. import com.backendsys.exception.CustException;
  7. import com.backendsys.modules.app.dao.AppUserDao;
  8. import com.backendsys.modules.app.entity.AppAuth;
  9. import com.backendsys.modules.app.entity.AppUser;
  10. import com.backendsys.modules.app.service.AppAuthService;
  11. import com.backendsys.modules.common.config.redis.utils.RedisUtil;
  12. import com.backendsys.modules.common.config.security.entity.SecurityAppUserInfo;
  13. import com.backendsys.modules.common.config.security.utils.*;
  14. import com.backendsys.modules.system.entity.TokenCatch;
  15. import com.backendsys.modules.system.service.SysCommonService;
  16. import com.backendsys.utils.response.ResultEnum;
  17. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  18. import org.springframework.beans.factory.annotation.Autowired;
  19. import org.springframework.beans.factory.annotation.Value;
  20. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  21. import org.springframework.stereotype.Service;
  22. import java.util.Date;
  23. import java.util.UUID;
  24. import java.util.concurrent.TimeUnit;
  25. @Service
  26. public class AppAuthServiceImpl implements AppAuthService {
  27. @Autowired
  28. private JwtUtil jwtUtil;
  29. @Autowired
  30. private TokenUtil tokenUtil;
  31. @Autowired
  32. private RedisUtil redisUtil;
  33. @Autowired
  34. private CaptchaUtil captchaUtil;
  35. @Autowired
  36. private LockStatusUtil lockStatusUtil;
  37. @Autowired
  38. private HttpRequestUtil httpRequestUtil;
  39. @Autowired
  40. private AppUserDao appUserDao;
  41. @Autowired
  42. private SysCommonService sysCommonService;
  43. @Value("${tencent.sms.debug}")
  44. private String SMS_DEBUG;
  45. @Value("${CAPTCHA_DURATION}")
  46. private Integer CAPTCHA_DURATION;
  47. @Value("${REDIS_LOGIN_TOKEN_PREFIX}")
  48. private String REDIS_LOGIN_TOKEN_PREFIX;
  49. @Value("${spring.application.name}")
  50. private String APPLICATION_NAME;
  51. private String redisKeyOfLogin = APPLICATION_NAME + "-app-sms-login";
  52. private String redisKeyOfRegister = APPLICATION_NAME + "-app-sms-register";
  53. private String redisKeyOfLoginFail = APPLICATION_NAME + "-app-login-error";
  54. private String redisKeyOfRegisterFail = APPLICATION_NAME + "-app-register-error";
  55. // [方法] 登录失败 (errMsg: 错误提示文本, phone: 手机号码, intercept: 是否拦截)
  56. private void loginFail(String errMsg, String phone, Boolean isIntercept) {
  57. // 删除图形验证码
  58. redisUtil.delete(httpRequestUtil.getKaptchaKey());
  59. // 添加登录错误的冻结标记
  60. if (isIntercept) lockStatusUtil.setLockStatus(redisKeyOfLoginFail, phone);
  61. throw new CustException(errMsg, ResultEnum.INVALID_CREDENTIALS.getCode());
  62. }
  63. // [方法] 登录成功
  64. private AppUser loginSuccess(AppUser appUser) {
  65. // 删除图形验证码缓存
  66. redisUtil.delete(httpRequestUtil.getKaptchaKey());
  67. // 删除旧的登录缓存
  68. tokenUtil.deleteRedisLoginToken(appUser.getLast_login_uuid());
  69. // 判断用户是否启用
  70. Integer status = appUser.getStatus();
  71. if (status != null && status.equals(-1)) throw new CustException("该用户已被禁用,请与客服联系");
  72. // 判断用户是否已删除
  73. Integer del_flag = appUser.getDel_flag();
  74. if (del_flag != null && del_flag.equals(1)) throw new CustException("当前用户不可用,请与客服联系");
  75. // 设置 最后一次的登录信息 (uuid, ip, 登录时间)
  76. String uuid = Convert.toStr(UUID.randomUUID());
  77. appUser.setUser_id(appUser.getId());
  78. appUser.setLast_login_uuid(uuid);
  79. appUser.setLast_login_ip(httpRequestUtil.getIpAddr());
  80. appUser.setLast_login_time(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
  81. appUserDao.updateById(appUser);
  82. // [系统配置] 微信用户默认登录过期时间(小时)
  83. Integer APP_USER_LOGIN_DURATION_DEFAULT = Convert.toInt(sysCommonService.getCommonByTag("APP_USER_LOGIN_DURATION_DEFAULT"));
  84. // 将小时转换为毫秒
  85. Long DEFAULT_MILLISECONDS = APP_USER_LOGIN_DURATION_DEFAULT * DateUnit.HOUR.getMillis();
  86. Integer token_duration_hours = Convert.toInt(DEFAULT_MILLISECONDS / 3600000L);
  87. Date token_expiration = new Date((new Date()).getTime() + DEFAULT_MILLISECONDS);
  88. appUser.setToken_expiration(DateUtil.format(token_expiration, "yyyy-MM-dd HH:mm:ss"));
  89. appUser.setRole("APP_USER");
  90. // 生成 Token
  91. SecurityAppUserInfo securityUserInfo = JSONUtil.toBean(JSONUtil.parseObj(appUser), SecurityAppUserInfo.class);
  92. String token = jwtUtil.createAppJwtToken(securityUserInfo);
  93. String token_redis_key = REDIS_LOGIN_TOKEN_PREFIX + uuid;
  94. appUser.setToken(token);
  95. // [Redis] 将 Token 存入缓存
  96. TokenCatch tokenCatch = new TokenCatch(token, null);
  97. redisUtil.setCacheObject(token_redis_key, JSONUtil.toJsonStr(tokenCatch), token_duration_hours, TimeUnit.HOURS);
  98. return appUser;
  99. }
  100. /**
  101. * APP登录 (用户名登录)
  102. */
  103. @Override
  104. public AppUser login(AppAuth appAuth) {
  105. String phone = appAuth.getPhone();
  106. String password = appAuth.getPassword();
  107. String captcha = appAuth.getCaptcha();
  108. // 判断是否处于登录错误的冻结状态 (2分钟内错误5次,则出现冻结提示)
  109. lockStatusUtil.checkLockStatus(redisKeyOfLoginFail, phone);
  110. // 判断图形验证码是否正确
  111. if (!captchaUtil.isCaptchaValid(captcha, httpRequestUtil.getKaptchaKey())) {
  112. loginFail("验证码错误", phone, false);
  113. return null;
  114. }
  115. // [Method] 判断 用户 是否存在 && 密码是否正确
  116. AppUser appUser = appUserDao.selectOne(new LambdaQueryWrapper<AppUser>().eq(AppUser::getPhone, phone));
  117. if (appUser == null) {
  118. // [登录失败] 用户不存在
  119. loginFail("手机号码或密码错误", phone, true);
  120. return null;
  121. } else {
  122. // [登录失败] 密码不正确
  123. BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
  124. if (!encoder.matches(password, appUser.getPassword())) {
  125. loginFail("手机号码或密码错误", phone, true);
  126. }
  127. // [登录成功]
  128. return loginSuccess(appUser);
  129. }
  130. }
  131. }