SysLoginService.java 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. package com.ruoyi.web.service;
  2. import javax.annotation.Resource;
  3. import com.google.common.collect.Maps;
  4. import com.ruoyi.common.core.domain.AjaxResult;
  5. import com.ruoyi.common.enums.ErrorCodes;
  6. import com.ruoyi.common.exception.ErrorException;
  7. import com.ruoyi.common.utils.PhoneUtils;
  8. import com.ruoyi.framework.web.service.TokenService;
  9. import com.ruoyi.system.service.ShortMessageService;
  10. import org.apache.commons.lang3.tuple.Pair;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.security.authentication.AuthenticationManager;
  13. import org.springframework.security.authentication.BadCredentialsException;
  14. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  15. import org.springframework.security.core.Authentication;
  16. import org.springframework.stereotype.Component;
  17. import com.ruoyi.common.constant.CacheConstants;
  18. import com.ruoyi.common.constant.Constants;
  19. import com.ruoyi.common.constant.UserConstants;
  20. import com.ruoyi.common.core.domain.model.LoginUser;
  21. import com.ruoyi.common.core.redis.RedisCache;
  22. import com.ruoyi.common.exception.ServiceException;
  23. import com.ruoyi.common.exception.user.BlackListException;
  24. import com.ruoyi.common.exception.user.CaptchaException;
  25. import com.ruoyi.common.exception.user.CaptchaExpireException;
  26. import com.ruoyi.common.exception.user.UserNotExistsException;
  27. import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
  28. import com.ruoyi.common.utils.DateUtils;
  29. import com.ruoyi.common.utils.MessageUtils;
  30. import com.ruoyi.common.utils.StringUtils;
  31. import com.ruoyi.common.utils.ip.IpUtils;
  32. import com.ruoyi.framework.manager.AsyncManager;
  33. import com.ruoyi.framework.manager.factory.AsyncFactory;
  34. import com.ruoyi.framework.security.context.AuthenticationContextHolder;
  35. import com.ruoyi.system.service.ISysConfigService;
  36. import com.ruoyi.system.service.ISysUserService;
  37. import org.springframework.transaction.annotation.Transactional;
  38. import java.util.Map;
  39. /**
  40. * 登录校验方法
  41. *
  42. * @author ruoyi
  43. */
  44. @Component
  45. public class SysLoginService
  46. {
  47. @Autowired
  48. private TokenService tokenService;
  49. @Resource
  50. private AuthenticationManager authenticationManager;
  51. @Autowired
  52. private RedisCache redisCache;
  53. @Autowired
  54. private ISysUserService userService;
  55. @Autowired
  56. private ISysConfigService configService;
  57. @Autowired
  58. private ShortMessageService shortMessageService;
  59. /**
  60. * 登录验证
  61. * @param mobile
  62. * @param username
  63. * @param password
  64. * @param code
  65. * @param uuid
  66. * @return
  67. */
  68. public AjaxResult login(String mobile, String username, String password, String code, String uuid) {
  69. if (StringUtils.isNotBlank(mobile)) {
  70. if (!shortMessageService.checkCode(mobile, password)) {
  71. AsyncManager.me().execute(AsyncFactory.recordLogininfor(mobile, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
  72. throw new CaptchaException();
  73. }
  74. loginMobilePreCheck(mobile, password);
  75. username = mobile;
  76. password = UserConstants.LOGIN_SMS_PASS;
  77. } else {
  78. // 验证码校验
  79. validateCaptcha(username, code, uuid);
  80. // 登录前置校验
  81. loginPreCheck(username, password);
  82. }
  83. // 用户验证
  84. Authentication authentication = null;
  85. try
  86. {
  87. UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
  88. AuthenticationContextHolder.setContext(authenticationToken);
  89. // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
  90. authentication = authenticationManager.authenticate(authenticationToken);
  91. }
  92. catch (Exception e)
  93. {
  94. if (e instanceof BadCredentialsException)
  95. {
  96. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
  97. throw new UserPasswordNotMatchException();
  98. }
  99. else
  100. {
  101. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
  102. if(e.getCause() instanceof ErrorException) {
  103. ErrorException errorException = (ErrorException) e.getCause();
  104. Map map = Maps.newHashMap();
  105. ErrorCodes errorCode = errorException.getErrorCode();
  106. map.put("code", errorCode.getCode());
  107. map.put("message", StringUtils.isNotEmpty(errorException.getMessage()) ? errorException.getMessage() : errorCode.getTitle());
  108. return AjaxResult.success(map);
  109. }
  110. throw new ServiceException(e.getMessage());
  111. }
  112. }
  113. finally
  114. {
  115. AuthenticationContextHolder.clearContext();
  116. }
  117. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
  118. LoginUser loginUser = (LoginUser) authentication.getPrincipal();
  119. recordLoginInfo(loginUser.getUserId());
  120. // 生成token
  121. AjaxResult ajax = AjaxResult.success();
  122. ajax.put(Constants.TOKEN, tokenService.createToken(loginUser));
  123. return ajax;
  124. }
  125. /**
  126. * 校验验证码
  127. *
  128. * @param username 用户名
  129. * @param code 验证码
  130. * @param uuid 唯一标识
  131. * @return 结果
  132. */
  133. public void validateCaptcha(String username, String code, String uuid)
  134. {
  135. boolean captchaEnabled = configService.selectCaptchaEnabled();
  136. if (captchaEnabled)
  137. {
  138. String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
  139. String captcha = redisCache.getCacheObject(verifyKey);
  140. if (captcha == null)
  141. {
  142. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
  143. throw new CaptchaExpireException();
  144. }
  145. redisCache.deleteObject(verifyKey);
  146. if (!code.equalsIgnoreCase(captcha))
  147. {
  148. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
  149. throw new CaptchaException();
  150. }
  151. }
  152. }
  153. /**
  154. * 登录前置校验
  155. * @param username 用户名
  156. * @param password 用户密码
  157. */
  158. public void loginPreCheck(String username, String password)
  159. {
  160. // 用户名或密码为空 错误
  161. if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
  162. {
  163. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
  164. throw new UserNotExistsException();
  165. }
  166. // 密码如果不在指定范围内 错误
  167. if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
  168. || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
  169. {
  170. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
  171. throw new UserPasswordNotMatchException();
  172. }
  173. // 用户名不在指定范围内 错误
  174. if (username.length() < UserConstants.USERNAME_MIN_LENGTH
  175. || username.length() > UserConstants.USERNAME_MAX_LENGTH)
  176. {
  177. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
  178. throw new UserPasswordNotMatchException();
  179. }
  180. // IP黑名单校验
  181. String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
  182. if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
  183. {
  184. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
  185. throw new BlackListException();
  186. }
  187. }
  188. public void loginMobilePreCheck(String phoneNumber, String code)
  189. {
  190. // 用户名或密码为空 错误
  191. if (StringUtils.isEmpty(phoneNumber) || StringUtils.isEmpty(code))
  192. {
  193. AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
  194. throw new UserNotExistsException();
  195. }
  196. // 密码如果不在指定范围内 错误
  197. if (code.length() != 4)
  198. {
  199. AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
  200. throw new UserPasswordNotMatchException();
  201. }
  202. // 用户名不在指定范围内 错误
  203. if (!PhoneUtils.isPhoneNumber(phoneNumber))
  204. {
  205. AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
  206. throw new UserPasswordNotMatchException();
  207. }
  208. // IP黑名单校验
  209. String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
  210. if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
  211. {
  212. AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
  213. throw new BlackListException();
  214. }
  215. }
  216. /**
  217. * 记录登录信息
  218. *
  219. * @param userId 用户ID
  220. */
  221. public void recordLoginInfo(Long userId)
  222. {
  223. userService.updateLoginInfo(userId, IpUtils.getIpAddr(), DateUtils.getNowDate());
  224. }
  225. }