UserServiceImpl.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. package com.uas.sso.service.impl;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.uas.sso.common.encrypt.MD5;
  5. import com.uas.sso.common.util.HttpUtil;
  6. import com.uas.sso.core.Const;
  7. import com.uas.sso.core.ICallable;
  8. import com.uas.sso.core.Status;
  9. import com.uas.sso.core.Type;
  10. import com.uas.sso.dao.UserDao;
  11. import com.uas.sso.dao.UserRecordDao;
  12. import com.uas.sso.entity.*;
  13. import com.uas.sso.exception.VisibleError;
  14. import com.uas.sso.logging.LoggerManager;
  15. import com.uas.sso.logging.SyncBufferedLogger;
  16. import com.uas.sso.logging.UserBufferedLogger;
  17. import com.uas.sso.service.*;
  18. import com.uas.sso.util.AccountTypeUtils;
  19. import com.uas.sso.util.ExecuteUtils;
  20. import org.springframework.beans.factory.annotation.Autowired;
  21. import org.springframework.data.domain.Page;
  22. import org.springframework.data.domain.PageRequest;
  23. import org.springframework.data.domain.Pageable;
  24. import org.springframework.data.jpa.domain.Specification;
  25. import org.springframework.stereotype.Service;
  26. import org.springframework.ui.ModelMap;
  27. import org.springframework.util.CollectionUtils;
  28. import org.springframework.util.StringUtils;
  29. import com.uas.sso.exception.AccountException;
  30. import javax.persistence.criteria.*;
  31. import java.sql.Timestamp;
  32. import java.util.ArrayList;
  33. import java.util.List;
  34. import java.util.Set;
  35. /**
  36. * 用户service实现类
  37. *
  38. * @author wangmh
  39. * @date 2018/1/2
  40. */
  41. @Service
  42. public class UserServiceImpl implements UserService {
  43. @Autowired
  44. private UserDao userDao;
  45. @Autowired
  46. private UserRecordDao userRecordDao;
  47. @Autowired
  48. private UserValidService userValidService;
  49. @Autowired
  50. private UserspaceService userspaceService;
  51. @Autowired
  52. private AppService appService;
  53. @Autowired
  54. private UserQuestionService userQuestionService;
  55. private UserBufferedLogger userLog = LoggerManager.getLogger(UserBufferedLogger.class);
  56. private SyncBufferedLogger syncLog = LoggerManager.getLogger(SyncBufferedLogger.class);
  57. @Override
  58. public User findByMobile(String mobile, String mobileArea) {
  59. return userDao.findByMobileAndMobileArea(mobile, mobileArea);
  60. }
  61. @Override
  62. public User findByMobile(String mobile) {
  63. return userDao.findByMobile(mobile);
  64. }
  65. @Override
  66. public boolean mobileHasRegistered(String mobile) {
  67. User user = userDao.findByMobile(mobile);
  68. if (user == null) {
  69. return false;
  70. }
  71. return true;
  72. }
  73. @Override
  74. public boolean emailHasRegistered(String email) {
  75. List<User> users = userDao.findByEmail(email);
  76. if (CollectionUtils.isEmpty(users)) {
  77. return false;
  78. }
  79. return true;
  80. }
  81. @Override
  82. public User register(User user) {
  83. String noEncryPwd = user.getPassword();
  84. // 校验手机号是否被注册
  85. if (mobileHasRegistered(user.getMobile())) {
  86. throw new VisibleError("该手机号已被注册");
  87. }
  88. // 由于现在不考虑手机号所属区域,默认为中国大陆
  89. if (StringUtils.isEmpty(user.getMobileArea())) {
  90. user.setMobileArea(Const.CONTINENT);
  91. }
  92. // 设置基本属性,手机号默认已认证
  93. user.setRegisterDate(new Timestamp(System.currentTimeMillis()));
  94. Long uu = userDao.findMaxUU();
  95. user.setUserUU(uu == null ? 10000 : (uu + 1));
  96. user.setSalt(String.valueOf(user.getUserUU()));
  97. user.setMobileValidCode((short) Status.AUTHENTICATED.getCode());
  98. user.setEmailValidCode((short) Status.NOT_APPLYING.getCode());
  99. user.setIdentityValidCode((short) Status.NOT_APPLYING.getCode());
  100. user.setPassword(getEncryPassword(Const.ENCRY_FORMAT, user.getPassword(), user.getSalt()));
  101. user.setUserRecord(new UserRecord());
  102. user.getUserRecord().setUser(user);
  103. user.getUserRecord().setUserUU(user.getUserUU());
  104. userDao.save(user);
  105. userLog.info(user, Type.UPDATE_REGISTER.getValue());
  106. // 同步到各个应用
  107. syncUserInfo(user.getUserUU(), noEncryPwd, "个人注册");
  108. return user;
  109. }
  110. @Override
  111. public String getEncryPassword(String format, String noEncryPwd, String salt) {
  112. if (StringUtils.isEmpty(format)) {
  113. return noEncryPwd;
  114. }
  115. // 超过32认为是已加密过的密文
  116. if (noEncryPwd.length() >= 32) {
  117. /// 之后添加日志时恢复
  118. //logger.error("用户密码加密", String.format("传递过来的密码(%s)必须是未加密的明文", noEncryPwd));
  119. throw new AccountException("invalid password");
  120. }
  121. // $password{$salt}
  122. String password = format.replace(Const.ENCRY_PARAM_PASSWORD, noEncryPwd);
  123. password = password.replace(Const.ENCRY_PARAM_SALT, salt == null ? "" : salt);
  124. return MD5.toMD5(password);
  125. }
  126. @Override
  127. public User save(User user) {
  128. user = userDao.save(user);
  129. /// 数据同步,先注释
  130. syncUserInfo(user, null, "修改用户信息");
  131. return user;
  132. }
  133. @Override
  134. public void checkPassword(Long userUU, String password, boolean isEncry) {
  135. // 根据用户uu号找到旧数据
  136. User oldUser = userDao.findByUserUU(userUU);
  137. if (oldUser == null) {
  138. throw new VisibleError("用户名或密码错误");
  139. }
  140. // 校验密码
  141. checkPassword(oldUser, password, isEncry);
  142. }
  143. @Override
  144. public void checkPasswordByMobile(String mobile, String password, boolean isEncry) {
  145. // 找到用户
  146. User oldUser = userDao.findByMobile(mobile);
  147. if (oldUser == null) {
  148. throw new VisibleError("用户名或密码错误");
  149. }
  150. // 校验密码
  151. checkPassword(oldUser, password, isEncry);
  152. }
  153. @Override
  154. public void checkPasswordByEmail(String email, String password, boolean isEncry) {
  155. // 找到用户
  156. List<User> oldUsers = userDao.findByEmailAndEmailValidCode(email, (short) Status.AUTHENTICATED.getCode());
  157. if (CollectionUtils.isEmpty(oldUsers)) {
  158. throw new VisibleError("该邮箱未认证,请使用手机号登录");
  159. }
  160. // 校验密码
  161. for (User oldUser : oldUsers) {
  162. checkPassword(oldUser, password, isEncry);
  163. }
  164. }
  165. @Override
  166. public int getPwdErrorCount(String username) {
  167. User user = findByUsername(username);
  168. if (user == null) {
  169. throw new VisibleError("用户名不存在");
  170. }
  171. if (user.getUserRecord() == null) {
  172. return 0;
  173. }
  174. return user.getUserRecord().getPwdErrorCount();
  175. }
  176. @Override
  177. public User findByUsername(String username) {
  178. String type = AccountTypeUtils.getAccountType(username);
  179. User user = null;
  180. if (AccountTypeUtils.MOBILE.equals(type)) {
  181. // 手机号
  182. user = userDao.findByMobile(username);
  183. } else if (AccountTypeUtils.EMAIL.equals(type)) {
  184. // 邮箱
  185. List<User> users = userDao.findByEmailAndEmailValidCode(username, (short) Status.AUTHENTICATED.getCode());
  186. // 认证邮箱只有一条记录,直接选择第一个
  187. if (!CollectionUtils.isEmpty(users)) {
  188. user = users.get(0);
  189. }
  190. } else if (AccountTypeUtils.UU_NUMBER.equals(type)) {
  191. // uu号
  192. user = userDao.findByUserUU(Long.valueOf(username));
  193. }
  194. return user;
  195. }
  196. /**
  197. * 校验用户密码
  198. *
  199. * @param oldUser 用户信息
  200. * @param password 需要校验的密码
  201. * @param isEncry 需校验的密码是否被加密
  202. */
  203. private void checkPassword(User oldUser, String password, boolean isEncry) {
  204. // 密码未加密,转换成加密后的密码
  205. String encryPassword = password;
  206. if (!isEncry) {
  207. encryPassword = getEncryPassword(Const.ENCRY_FORMAT, password, oldUser.getSalt());
  208. }
  209. // 校验密码
  210. if (!encryPassword.equals(oldUser.getPassword())) {
  211. throw new VisibleError("密码不一致");
  212. }
  213. }
  214. @Override
  215. public UserRecord save(UserRecord userRecord) {
  216. return userRecordDao.save(userRecord);
  217. }
  218. @Override
  219. public User findOne(Long userUU) {
  220. return userDao.findOne(userUU);
  221. }
  222. @Override
  223. public boolean realNameIsValid(String realName) {
  224. User user = userDao.findByRealName(realName);
  225. if (user != null && user.getIdentityValidCode() == Status.AUTHENTICATED.getCode()) {
  226. return true;
  227. }
  228. return false;
  229. }
  230. @Override
  231. public boolean idCardIsValid(String idCard) {
  232. User user = userDao.findByIdCard(idCard);
  233. if (user != null && user.getIdentityValidCode() == Status.AUTHENTICATED.getCode()) {
  234. return true;
  235. }
  236. return false;
  237. }
  238. @Override
  239. public void submitIdValidInfo(User user) {
  240. // 校验企业名和营业执照是否被认证
  241. boolean isValid = realNameIsValid(user.getRealName());
  242. if (isValid) {
  243. throw new VisibleError("该真实姓名已被认证,请确认");
  244. }
  245. isValid = idCardIsValid(user.getIdCard());
  246. if (isValid) {
  247. throw new VisibleError("该身份证号已被认证,请确认");
  248. }
  249. User oldUser = userDao.findByUserUU(user.getUserUU());
  250. oldUser.setIdentityValidCode((short) Status.TO_BE_CERTIFIED.getCode());
  251. userDao.save(oldUser);
  252. // 保存日志
  253. userValidService.submitValid(user);
  254. }
  255. @Override
  256. public void updateMobile(Long userUU, String newMobile) {
  257. // 获取用户信息
  258. User user = userDao.findOne(userUU);
  259. if (user == null) {
  260. throw new VisibleError("用户不存在");
  261. }
  262. // 修改手机号
  263. user.setMobile(newMobile);
  264. user.setMobileValidCode((short) Status.AUTHENTICATED.getCode());
  265. // 保存用户信息
  266. userDao.save(user);
  267. // 保存日志
  268. userLog.info(user, Type.UPDATE_MOBILE.getValue());
  269. // 同步到各个应用
  270. syncUserInfo(user.getUserUU(), null, "个人注册");
  271. }
  272. @Override
  273. public void updateEmail(Long userUU, String newEmail) {
  274. // 获取用户信息
  275. User user = userDao.findOne(userUU);
  276. if (user == null) {
  277. throw new VisibleError("用户不存在");
  278. }
  279. // 修改手机号
  280. user.setEmail(newEmail);
  281. user.setEmailValidCode((short) Status.AUTHENTICATED.getCode());
  282. // 保存用户信息
  283. userDao.save(user);
  284. // 保存日志
  285. userLog.info(user, Type.UPDATE_EMAIL.getValue());
  286. // 同步信息到各应用
  287. syncUserInfo(user.getUserUU(), null, "修改邮箱");
  288. }
  289. @Override
  290. public Page<User> findMemberBySpaceUU(int page, int size, final Long spaceUU) {
  291. Pageable pageable = PageInfo.pageRequest(new PageRequest(page, size));
  292. Page<User> pUsers = userDao.findAll(new Specification<User>() {
  293. @Override
  294. public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
  295. List<Predicate> list = new ArrayList<>();
  296. list.add(cb.equal(root.join("userSpaces", JoinType.INNER).get("spaceUU").as(Long.class), spaceUU));
  297. Predicate[] predicates = new Predicate[list.size()];
  298. predicates = list.toArray(predicates);
  299. return cb.and(predicates);
  300. }
  301. }, pageable);
  302. return new PageInfo<User>(pUsers.getContent(), pageable, pUsers.getTotalElements());
  303. }
  304. @Override
  305. public void bindUserspace(String appId, Long userUU, Long spaceUU) {
  306. // 找到用户和企业
  307. User user = findOne(userUU);
  308. Userspace userspace = userspaceService.findOne(spaceUU);
  309. // 将企业添加到用户列表上
  310. Set<Userspace> userspaces = user.getUserSpaces();
  311. userspaces.add(userspace);
  312. // 保存
  313. userDao.save(user);
  314. syncUserBindSpace(userUU, spaceUU);
  315. // 保存日志
  316. userLog.info(user, Type.BIND_USERSPACE.getValue()+spaceUU);
  317. }
  318. /**
  319. * 同步用户绑定企业关系
  320. * @param userUU 用户uu号
  321. * @param spaceUU 企业uu号
  322. */
  323. private void syncUserBindSpace(Long userUU, Long spaceUU) {
  324. syncRelation(userUU, spaceUU, "bind");
  325. }
  326. /**
  327. * 同步用户解除绑定企业关系
  328. * @param userUU 用户uu号
  329. * @param spaceUU 企业uu号
  330. */
  331. private void syncUserUnbindSpace(Long userUU, Long spaceUU) {
  332. syncRelation(userUU, spaceUU, "unbind");
  333. }
  334. /**
  335. * 同步用户与企业的关系
  336. * @param userUU 用户uu号
  337. * @param spaceUU 企业uu号
  338. * @param type 类型 (bind or unbind)
  339. */
  340. private void syncRelation(final Long userUU, final Long spaceUU, final String type) {
  341. List<String> apps = appService.findUid();
  342. ExecuteUtils.execute(new ICallable<Void, String>() {
  343. @Override
  344. public Void call(String appId) {
  345. App tempApp = appService.findOne(appId);
  346. if (tempApp != null && StringUtils.isEmpty(tempApp.getUserControl())
  347. && !StringUtils.isEmpty(tempApp.getBackRelationUrl())) {
  348. String url = tempApp.getBackRelationUrl();
  349. ModelMap formData = new ModelMap();
  350. formData.put("userUU", userUU);
  351. formData.put("spaceUU", spaceUU);
  352. formData.put("type", type);
  353. HttpUtil.ResponseWrap res = null;
  354. try {
  355. res = HttpUtil.doPost(url, formData, 30000);
  356. if (!res.isSuccess()) {
  357. syncLog.error(appId, "同步绑定信息失败", JSON.toJSONString(formData), res.getContent());
  358. } else {
  359. syncLog.info(appId, "同步绑定信息成功", JSON.toJSONString(formData));
  360. }
  361. } catch (Exception e) {
  362. syncLog.error(appId, "同步绑定信息失败", JSON.toJSONString(formData), e.getMessage());
  363. }
  364. }
  365. return null;
  366. }
  367. }, apps);
  368. }
  369. @Override
  370. public void unbindUserspace(Long userUU, Long spaceUU) {
  371. // 找到用户和企业
  372. User user = findOne(userUU);
  373. if (user == null) {
  374. throw new VisibleError("未找到用户信息");
  375. }
  376. Userspace userspace = userspaceService.findOne(spaceUU);
  377. if (userspace == null) {
  378. throw new VisibleError("未找到企业信息");
  379. }
  380. // 将企业添加到用户列表上
  381. Set<Userspace> userspaces = user.getUserSpaces();
  382. userspaces.remove(userspace);
  383. // 保存
  384. userDao.save(user);
  385. syncUserUnbindSpace(userUU, spaceUU);
  386. // 保存日志
  387. userLog.info(user, Type.UNBIND_USERSPACE.getValue()+spaceUU);
  388. }
  389. @Override
  390. public void setQuestion(Long userUU, List<UserQuestion> questions) {
  391. // 找到用户密保
  392. User user = userDao.findOne(userUU);
  393. List<UserQuestion> userQuestions = user.getQuestions();
  394. // 清空旧的并添加新的
  395. if (CollectionUtils.isEmpty(userQuestions)) {
  396. user.setQuestions(questions);
  397. } else {
  398. for (int i=0; i<questions.size(); i++) {
  399. if (userQuestions.get(i) == null) {
  400. user.getQuestions().add(questions.get(i));
  401. } else {
  402. userQuestions.get(i).setQuestion(questions.get(i).getQuestion());
  403. userQuestions.get(i).setAnswer(questions.get(i).getAnswer());
  404. userQuestions.get(i).setSort(questions.get(i).getSort());
  405. }
  406. }
  407. }
  408. // 保存并添加日志
  409. user = userDao.save(user);
  410. userLog.info(user, Type.UPDATE_QUESTION.getValue(), JSON.toJSONString(user.getQuestions()));
  411. }
  412. @Override
  413. public List<String> findRepeatEmail() {
  414. return userDao.findRepeatEmail();
  415. }
  416. @Override
  417. public List<User> findByEmail(String email) {
  418. return userDao.findByEmail(email);
  419. }
  420. @Override
  421. public User updatePassword(Long userUU, String noEncryPwd) {
  422. User user = userDao.findOne(userUU);
  423. if (user == null) {
  424. throw new VisibleError("该用户不存在");
  425. }
  426. user.setPassword(getEncryPassword(Const.ENCRY_FORMAT, noEncryPwd, user.getSalt()));
  427. syncUserInfo(user , noEncryPwd, "用户修改密码");
  428. return userDao.save(user);
  429. }
  430. @Override
  431. public List<UserSpaceDetailInfo> findUserByTels(List<String> tels) {
  432. return userDao.findUsersByTels(tels);
  433. }
  434. /**
  435. * 同步用户信息到各个应用
  436. * @param userUU 用户uu号
  437. * @param noEncryPwd 未加密密码,用于同步im
  438. * @param msg 同步信息描述,用户区分同步类型
  439. */
  440. private void syncUserInfo(Long userUU, String noEncryPwd, String msg) {
  441. syncUserInfo(findOne(userUU), noEncryPwd, msg);
  442. }
  443. /**
  444. * 同步用户信息到各个应用
  445. * @param user 用户信息
  446. * @param noEncryPwd 未加密密码,用于同步im
  447. * @param msg 同步信息描述,用户区分同步类型
  448. */
  449. private void syncUserInfo(User user, String noEncryPwd, final String msg) {
  450. List<String> apps = appService.findUid();
  451. try {
  452. // 同步信息到im
  453. String imId = syncUserToIm(user, noEncryPwd);
  454. user.setImId(imId);
  455. user = userDao.save(user);
  456. } catch (Exception e) {
  457. e.printStackTrace();
  458. }
  459. User finalUser = user;
  460. ExecuteUtils.execute(new ICallable<Void, String>() {
  461. @Override
  462. public Void call(String appId) {
  463. App tempApp = appService.findOne(appId);
  464. if (tempApp != null && StringUtils.isEmpty(tempApp.getUserControl())
  465. && !StringUtils.isEmpty(tempApp.getBackUserUrl())) {
  466. String url = tempApp.getBackUserUrl();
  467. JSONObject formData = JSON.parseObject(JSON.toJSONString(finalUser));
  468. formData.put("password", finalUser.getPassword());
  469. HttpUtil.ResponseWrap res = null;
  470. try {
  471. res = HttpUtil.doPost(url, formData, 30000);
  472. if (!res.isSuccess()) {
  473. syncLog.error(appId, msg + ",同步用户信息失败", JSON.toJSONString(finalUser), res.getContent());
  474. } else {
  475. syncLog.info(appId, msg + ",同步用户信息成功", JSON.toJSONString(finalUser));
  476. }
  477. } catch (Exception e) {
  478. syncLog.error(appId, msg + ",同步用户信息失败", JSON.toJSONString(finalUser), e.getMessage());
  479. }
  480. }
  481. return null;
  482. }
  483. }, apps);
  484. }
  485. private String syncUserToIm(User user, String noEncryPwd) throws Exception {
  486. String appId = "im";
  487. App app = appService.findOne(appId);
  488. if (!StringUtils.isEmpty(app.getBackUserUrl())) {
  489. String url = app.getBackUserUrl();
  490. HttpUtil.ResponseWrap res = null;
  491. ModelMap formData = new ModelMap();
  492. formData.put("email", user.getEmail());
  493. formData.put("idCard", user.getIdCard());
  494. formData.put("name", user.getVipName());
  495. formData.put("sex", user.getSex());
  496. formData.put("mobile", user.getMobile());
  497. formData.put("password", noEncryPwd);
  498. formData.put("dialectUID", user.getImId());
  499. res = HttpUtil.doPost(url, formData, 30000);
  500. if (!res.isSuccess()) {
  501. throw new Exception(res.getContent());
  502. } else {
  503. JSONObject obj = JSON.parseObject(res.getContent());
  504. return String.valueOf(obj.get("dialectUID"));
  505. }
  506. }
  507. return null;
  508. }
  509. public UserView findOneView(Long userUU) {
  510. User user = findOne(userUU);
  511. return user.toView();
  512. }
  513. }