SysLoginService.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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.core.domain.entity.SysUser;
  6. import com.ruoyi.common.enums.ErrorCodes;
  7. import com.ruoyi.common.exception.ErrorException;
  8. import com.ruoyi.common.utils.PhoneUtils;
  9. import com.ruoyi.dz.domain.DzCards;
  10. import com.ruoyi.dz.service.IDzCardsService;
  11. import com.ruoyi.dz.service.impl.DzCardsServiceImpl;
  12. import com.ruoyi.framework.web.service.TokenService;
  13. import com.ruoyi.system.service.ShortMessageService;
  14. import com.ruoyi.web.controller.dz.DzCardsController;
  15. import org.apache.commons.collections4.CollectionUtils;
  16. import org.apache.commons.lang3.tuple.Pair;
  17. import org.springframework.beans.factory.annotation.Autowired;
  18. import org.springframework.security.authentication.AuthenticationManager;
  19. import org.springframework.security.authentication.BadCredentialsException;
  20. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  21. import org.springframework.security.core.Authentication;
  22. import org.springframework.stereotype.Component;
  23. import com.ruoyi.common.constant.CacheConstants;
  24. import com.ruoyi.common.constant.Constants;
  25. import com.ruoyi.common.constant.UserConstants;
  26. import com.ruoyi.common.core.domain.model.LoginUser;
  27. import com.ruoyi.common.core.redis.RedisCache;
  28. import com.ruoyi.common.exception.ServiceException;
  29. import com.ruoyi.common.exception.user.BlackListException;
  30. import com.ruoyi.common.exception.user.CaptchaException;
  31. import com.ruoyi.common.exception.user.CaptchaExpireException;
  32. import com.ruoyi.common.exception.user.UserNotExistsException;
  33. import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
  34. import com.ruoyi.common.utils.DateUtils;
  35. import com.ruoyi.common.utils.MessageUtils;
  36. import com.ruoyi.common.utils.StringUtils;
  37. import com.ruoyi.common.utils.ip.IpUtils;
  38. import com.ruoyi.framework.manager.AsyncManager;
  39. import com.ruoyi.framework.manager.factory.AsyncFactory;
  40. import com.ruoyi.framework.security.context.AuthenticationContextHolder;
  41. import com.ruoyi.system.service.ISysConfigService;
  42. import com.ruoyi.system.service.ISysUserService;
  43. import org.springframework.transaction.annotation.Transactional;
  44. import java.util.Arrays;
  45. import java.util.List;
  46. import java.util.Map;
  47. /**
  48. * 登录校验方法
  49. *
  50. * @author ruoyi
  51. */
  52. @Component
  53. public class SysLoginService
  54. {
  55. @Autowired
  56. private TokenService tokenService;
  57. @Resource
  58. private AuthenticationManager authenticationManager;
  59. @Autowired
  60. private RedisCache redisCache;
  61. @Autowired
  62. private ISysUserService userService;
  63. @Autowired
  64. private ISysConfigService configService;
  65. @Autowired
  66. private ShortMessageService shortMessageService;
  67. @Autowired
  68. private IDzCardsService cardsService;
  69. /**
  70. * 登录验证
  71. * @param mobile
  72. * @param username
  73. * @param password
  74. * @param code
  75. * @param uuid
  76. * @return
  77. */
  78. public AjaxResult login(String mobile, String username, String password, String code, String uuid) {
  79. if (StringUtils.isNotBlank(mobile)) {
  80. //手机验证码登录:{code: "9", uuid: "cc94320c3fce4db5898213b727ac1dc0", mobile: "18774924158", password: "1234"}
  81. if (!shortMessageService.checkCode(mobile, password)) {
  82. AsyncManager.me().execute(AsyncFactory.recordLogininfor(mobile, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
  83. throw new CaptchaException();
  84. }
  85. loginMobilePreCheck(mobile, password);
  86. username = mobile;
  87. password = UserConstants.LOGIN_SMS_PASS;
  88. } else {
  89. // 验证码校验
  90. // 卡密登录json:{code: "0", uuid: "a9eee0b6729f42c4862a57acef8a4bdd", username: "20000025", password: "123456"}
  91. validateCaptcha(username, code, uuid);
  92. // 登录前置校验
  93. loginPreCheck(username, password);
  94. //卡密登录时,要将卡的密码转换为用户的密码
  95. DzCards card = cardsService.selectDzCardsByCardNo(username);
  96. if (null==card){
  97. return AjaxResult.error("卡不存在");
  98. }
  99. if (!password.trim().equalsIgnoreCase(card.getPassword())){
  100. return AjaxResult.error("密码错误");
  101. }
  102. String dbPwd = userService.selectPasswordByCardId(card.getCardId());
  103. if (StringUtils.isNotEmpty(dbPwd)){
  104. password = dbPwd;
  105. }
  106. }
  107. // 用户验证
  108. Authentication authentication = null;
  109. try
  110. {
  111. UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
  112. AuthenticationContextHolder.setContext(authenticationToken);
  113. // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
  114. authentication = authenticationManager.authenticate(authenticationToken);
  115. }
  116. catch (Exception e)
  117. {
  118. if (e instanceof BadCredentialsException)
  119. {
  120. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
  121. throw new UserPasswordNotMatchException();
  122. }
  123. else
  124. {
  125. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
  126. if(e.getCause() instanceof ErrorException) {
  127. ErrorException errorException = (ErrorException) e.getCause();
  128. Map map = Maps.newHashMap();
  129. ErrorCodes errorCode = errorException.getErrorCode();
  130. map.put("code", errorCode.getCode());
  131. map.put("message", StringUtils.isNotEmpty(errorException.getMessage()) ? errorException.getMessage() : errorCode.getTitle());
  132. return AjaxResult.success(map);
  133. }
  134. throw new ServiceException(e.getMessage());
  135. }
  136. }
  137. finally
  138. {
  139. AuthenticationContextHolder.clearContext();
  140. }
  141. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
  142. LoginUser loginUser = (LoginUser) authentication.getPrincipal();
  143. recordLoginInfo(loginUser.getUserId());
  144. // 生成token
  145. AjaxResult ajax = AjaxResult.success();
  146. ajax.put(Constants.TOKEN, tokenService.createToken(loginUser));
  147. return ajax;
  148. }
  149. /**
  150. * 内部自动登陆,不记录日志
  151. * @param username
  152. * @param password
  153. * @return
  154. */
  155. public String loginInner(String username, String password) {
  156. // 用户验证
  157. Authentication authentication = null;
  158. try
  159. {
  160. UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
  161. AuthenticationContextHolder.setContext(authenticationToken);
  162. // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
  163. authentication = authenticationManager.authenticate(authenticationToken);
  164. }
  165. catch (Exception e)
  166. {
  167. if (e instanceof BadCredentialsException)
  168. {
  169. throw new UserPasswordNotMatchException();
  170. }
  171. else
  172. {
  173. throw new ServiceException(e.getMessage());
  174. }
  175. }
  176. finally
  177. {
  178. AuthenticationContextHolder.clearContext();
  179. }
  180. LoginUser loginUser = (LoginUser) authentication.getPrincipal();
  181. return tokenService.createToken(loginUser);
  182. }
  183. /**
  184. * 校验验证码
  185. *
  186. * @param username 用户名
  187. * @param code 验证码
  188. * @param uuid 唯一标识
  189. * @return 结果
  190. */
  191. public void validateCaptcha(String username, String code, String uuid)
  192. {
  193. boolean captchaEnabled = configService.selectCaptchaEnabled();
  194. if (captchaEnabled)
  195. {
  196. String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
  197. String captcha = redisCache.getCacheObject(verifyKey);
  198. if (captcha == null)
  199. {
  200. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
  201. throw new CaptchaExpireException();
  202. }
  203. redisCache.deleteObject(verifyKey);
  204. if (!code.equalsIgnoreCase(captcha))
  205. {
  206. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
  207. throw new CaptchaException();
  208. }
  209. }
  210. }
  211. /**
  212. * 登录前置校验
  213. * @param username 用户名
  214. * @param password 用户密码
  215. */
  216. public void loginPreCheck(String username, String password)
  217. {
  218. // 用户名或密码为空 错误
  219. if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
  220. {
  221. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
  222. throw new UserNotExistsException();
  223. }
  224. // 密码如果不在指定范围内 错误
  225. if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
  226. || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
  227. {
  228. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
  229. throw new UserPasswordNotMatchException();
  230. }
  231. // 用户名不在指定范围内 错误
  232. if (username.length() < UserConstants.USERNAME_MIN_LENGTH
  233. || username.length() > UserConstants.USERNAME_MAX_LENGTH)
  234. {
  235. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
  236. throw new UserPasswordNotMatchException();
  237. }
  238. // IP黑名单校验
  239. String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
  240. if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
  241. {
  242. AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
  243. throw new BlackListException();
  244. }
  245. }
  246. public void loginMobilePreCheck(String phoneNumber, String code)
  247. {
  248. // 用户名或密码为空 错误
  249. if (StringUtils.isEmpty(phoneNumber) || StringUtils.isEmpty(code))
  250. {
  251. AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
  252. throw new UserNotExistsException();
  253. }
  254. // 密码如果不在指定范围内 错误
  255. if (code.length() != 4)
  256. {
  257. AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
  258. throw new UserPasswordNotMatchException();
  259. }
  260. // 用户名不在指定范围内 错误
  261. if (!PhoneUtils.isPhoneNumber(phoneNumber))
  262. {
  263. AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
  264. throw new UserPasswordNotMatchException();
  265. }
  266. // IP黑名单校验
  267. String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
  268. if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
  269. {
  270. AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
  271. throw new BlackListException();
  272. }
  273. }
  274. /**
  275. * 记录登录信息
  276. *
  277. * @param userId 用户ID
  278. */
  279. public void recordLoginInfo(Long userId)
  280. {
  281. userService.updateLoginInfo(userId, IpUtils.getIpAddr(), DateUtils.getNowDate());
  282. }
  283. }