AbstractLoginService.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. package com.ytpm.handle;
  2. import cn.hutool.core.util.IdUtil;
  3. import cn.hutool.core.util.RandomUtil;
  4. import cn.hutool.core.util.StrUtil;
  5. import com.ytpm.agent.enums.UserStatusEnum;
  6. import com.ytpm.app.enums.LoginType;
  7. import com.ytpm.app.model.YtDyzLoginRecord;
  8. import com.ytpm.app.model.YtDyzUser;
  9. import com.ytpm.app.param.LoginParam;
  10. import com.ytpm.app.view.WxDefaultConfig;
  11. import com.ytpm.general.RepMessage;
  12. import com.ytpm.general.Result;
  13. import com.ytpm.util.IPUtil;
  14. import lombok.extern.slf4j.Slf4j;
  15. import org.springframework.beans.factory.annotation.Value;
  16. import org.springframework.util.CollectionUtils;
  17. import javax.servlet.http.HttpServletRequest;
  18. import java.util.Date;
  19. import java.util.HashMap;
  20. import java.util.List;
  21. import java.util.Map;
  22. import java.util.Objects;
  23. /**
  24. * <p>登陆模板</p>
  25. * 兼容多登陆模式及风控校验
  26. * <p>需重写方法:<br>
  27. * 1.登陆参数校验 validateParams
  28. * 2.根据设备及渠道ID查询用户 queryUserByDeviceAndDitch
  29. * 3.获取登陆默认配置 getLoginConfig
  30. * 4.根据登陆参数获取系统用户 queryDyzUserByParam
  31. * 5.用户新注册逻辑 registryUser
  32. * 6.已注册用户处理逻辑 deadWithUserCrud
  33. * 7.登陆记录保存 saveLoginRecord
  34. * 8.远程调用风控 remoteCheckLoginRisk
  35. * 9.远程调用风控 remoteCheckRegRisk
  36. * </p>
  37. *
  38. * <p>回调方法:<br>
  39. * 1.用户注册时回调 beforeRegistryUser<br>
  40. * 2.用户登陆时回调 beforeDeadWithUserCrud
  41. * </p>
  42. *
  43. * <p>可选重写方法:<br>
  44. * 1.第三方登陆调用处理及参数传递 setThirdPartyLoginInfo <br>
  45. * 2.登陆成功后调用风控服务校验 ytRiskValidate
  46. * 3.登陆用户信息配置额外信息 setExtInfo
  47. * </p>
  48. *
  49. * @author lih
  50. * @date 2025/9/4
  51. */
  52. @Slf4j
  53. public abstract class AbstractLoginService {
  54. @Value("${risk.config.banned.tips}")
  55. private String tips;
  56. @Value("${spring.application.name:}")
  57. private String applicationName;
  58. protected abstract LoginType getLoginType();
  59. /**
  60. * 登陆逻辑处理
  61. * @param loginParam 登陆参数
  62. * @param request request
  63. * @return YtDyzUser
  64. */
  65. public final YtDyzUser loginHandle(LoginParam loginParam, HttpServletRequest request) {
  66. loginParam.setLoginIp(IPUtil.getClientIp(request));
  67. // 获取默认配置
  68. WxDefaultConfig defaultConfig = getLoginConfig(loginParam.getAppType());
  69. if (Objects.isNull(defaultConfig)) {
  70. throw new CommonException(StrUtil.format("{}登录失败,未找到相应配置!", getLoginType().getTypeName()));
  71. }
  72. loginParam.setAppId(defaultConfig.getPlatformAppId());
  73. // 参数校验
  74. validateParams(loginParam, request);
  75. // 获取第三方登陆信息 如微信授权码、微信登陆后授权信息
  76. Map<String, Object> paramMap = setThirdPartyLoginInfo(loginParam, defaultConfig, request);
  77. YtDyzUser ytDyzUser;
  78. if (getLoginType() == LoginType.VISITOR) {
  79. // 游客模式
  80. paramMap.put("defaultConfig", defaultConfig);
  81. ytDyzUser = visitorLoginHandle(loginParam, paramMap);
  82. } else {
  83. ytDyzUser = clientLoginHandle(loginParam, paramMap);
  84. }
  85. // 配置额外信息
  86. setExtInfo(ytDyzUser, paramMap);
  87. // 添加用户登录记录
  88. addLoginRecord(loginParam,ytDyzUser);
  89. // 调用风控服务校验默认风控配置
  90. ytRiskValidate(ytDyzUser, paramMap);
  91. // 游客登陆 校验通过 更新用户状态为正常
  92. if (getLoginType() == LoginType.VISITOR) {
  93. updateUserStatus(ytDyzUser, UserStatusEnum.NORMAL, null);
  94. }
  95. return ytDyzUser;
  96. }
  97. protected abstract void updateUserStatus(YtDyzUser ytDyzUser, UserStatusEnum statusEnum, String reason);
  98. /**
  99. * 登陆参数校验
  100. */
  101. protected abstract void validateParams(LoginParam loginParam, HttpServletRequest request);
  102. /**
  103. * 微信端/IOS端登陆
  104. */
  105. private YtDyzUser clientLoginHandle(LoginParam loginParam, Map<String, Object> paramMap) {
  106. YtDyzUser ytDyzUser;
  107. List<YtDyzUser> ytDyzUsers = queryDyzUserByParam(loginParam, paramMap);
  108. if (CollectionUtils.isEmpty(ytDyzUsers)) {
  109. beforeRegistryUser(loginParam, paramMap);
  110. ytDyzUser = new YtDyzUser();
  111. registryUser(loginParam, ytDyzUser, paramMap);
  112. } else {
  113. ytDyzUser = ytDyzUsers.get(0);
  114. beforeDeadWithUserCrud(loginParam, ytDyzUser, paramMap);
  115. deadWithUserCrud(loginParam, ytDyzUser, paramMap);
  116. }
  117. ytDyzUser.setLoginType(LoginType.WX);
  118. return ytDyzUser;
  119. }
  120. /**
  121. * 游客模式登录
  122. */
  123. private YtDyzUser visitorLoginHandle(LoginParam loginParam, Map<String, Object> paramMap) {
  124. // 唯一性判断
  125. YtDyzUser ytDyzUser = queryUserByDeviceAndDitch(loginParam.getDeviceId(), loginParam.getDitchId());
  126. if(ytDyzUser == null) {
  127. log.warn(StrUtil.format("visitor register[ deviceId:{}, ditchId: {}]",
  128. loginParam.getDeviceId(), loginParam.getDitchId()));
  129. beforeRegistryUser(loginParam, paramMap);
  130. ytDyzUser = new YtDyzUser();
  131. registryUser(loginParam, ytDyzUser, paramMap);
  132. } else {
  133. log.warn(StrUtil.format("visitor login[ deviceId:{}, ditchId: {}]",
  134. loginParam.getDeviceId(), loginParam.getDitchId()));
  135. //当前渠道已有用户,校验用户是否处于风控中 & 更新用户信息
  136. beforeDeadWithUserCrud(loginParam, ytDyzUser, paramMap);
  137. //如果当前登录是本日第一次登录则登录天数+1
  138. //202550916 游客登陆不记录登陆信息
  139. deadWithUserCrud(loginParam, ytDyzUser, paramMap);
  140. }
  141. // 保存游客广告信息
  142. WxDefaultConfig defaultConfig = (WxDefaultConfig) paramMap.get("defaultConfig");
  143. saveVisitorAdRecord(ytDyzUser, loginParam, defaultConfig);
  144. ytDyzUser.setLoginType(LoginType.VISITOR);
  145. return ytDyzUser;
  146. }
  147. // 游客登陆时保存传递记录
  148. protected void saveVisitorAdRecord(YtDyzUser ytDyzUser, LoginParam loginParam, WxDefaultConfig defaultConfig) {
  149. }
  150. /**
  151. * 根据设备及渠道ID查询用户
  152. */
  153. protected abstract YtDyzUser queryUserByDeviceAndDitch(String deviceId, Long ditchId);
  154. /**
  155. * 第三方登陆调用处理及参数传递
  156. */
  157. protected Map<String, Object> setThirdPartyLoginInfo(LoginParam loginParam, WxDefaultConfig defaultConfig,
  158. HttpServletRequest request) {
  159. Map<String, Object> map = new HashMap<>();
  160. return map;
  161. }
  162. /**
  163. * 获取登陆默认配置
  164. */
  165. protected abstract WxDefaultConfig getLoginConfig(Integer appType);
  166. /**
  167. * 根据登陆配置信息 查询系统用户记录
  168. * @param loginParam 登陆参数
  169. * @param thirdPartyLoginInfo 第三方登陆西悉尼
  170. */
  171. protected abstract List<YtDyzUser> queryDyzUserByParam(LoginParam loginParam, Map<String, Object> thirdPartyLoginInfo);
  172. // 注册用户处理器回调
  173. protected void beforeRegistryUser(LoginParam loginParam, Map<String, Object> paramMap){
  174. }
  175. // 用户注册逻辑
  176. protected abstract YtDyzUser registryUser(LoginParam loginParam,YtDyzUser user, Map<String, Object> paramMap);
  177. // 已注册用户处理前回调
  178. protected void beforeDeadWithUserCrud(LoginParam loginParam, YtDyzUser ytDyzUser, Map<String, Object> paramMap){
  179. //当前渠道已有用户,校验用户是否处于风控中 & 更新用户信息
  180. if(ytDyzUser != null && !ytDyzUser.getUserStatus().equals(UserStatusEnum.NORMAL.getCode())
  181. && !ytDyzUser.getUserStatus().equals(UserStatusEnum.VISITOR_LOCK.getCode())){
  182. throw new CommonException(getTipsMsg());
  183. }
  184. }
  185. private String getTipsMsg(){
  186. String[] split = tips.split(",");
  187. return split[RandomUtil.randomInt(split.length)];
  188. }
  189. // 已注册用户处理逻辑
  190. protected abstract void deadWithUserCrud(LoginParam loginParam, YtDyzUser old, Map<String, Object> paramMap);
  191. private void addLoginRecord(LoginParam param, YtDyzUser old) {
  192. YtDyzLoginRecord loginRecord = new YtDyzLoginRecord();
  193. loginRecord.setRecordId(IdUtil.fastSimpleUUID());
  194. loginRecord.setUserId(old.getUserId());
  195. loginRecord.setLoginTime(new Date());
  196. loginRecord.setDeviceBrand(param.getBrand());
  197. loginRecord.setDeviceModel(param.getModel());
  198. loginRecord.setLoginIp(param.getLoginIp());
  199. loginRecord.setOperator(param.getIpOperator());
  200. loginRecord.setIpAddr(param.getIpLocation());
  201. loginRecord.setPhoneJson(param.getPhoneJson());
  202. loginRecord.setLoginType(old.getLoginType().toString());
  203. saveLoginRecord(loginRecord);
  204. }
  205. /**
  206. * 保存登陆记录实现
  207. */
  208. protected abstract void saveLoginRecord(YtDyzLoginRecord loginRecord);
  209. /**
  210. * 调用风控服务校验默认风控配置
  211. */
  212. protected void ytRiskValidate(YtDyzUser ytDyzUser, Map<String, Object> paramMap) {
  213. Result<?> result = remoteCheckLoginRisk(ytDyzUser);
  214. if (result == null) {
  215. throw new CommonException("feign invoke Fail!");
  216. }
  217. if (result.getCode() != 200) {
  218. String errorMessage = result.getMessage();
  219. if (ytDyzUser.getLoginType() == LoginType.VISITOR && RepMessage.RISK_VISITOR_LOWER_VALUE.equals(errorMessage)) {
  220. WxDefaultConfig defaultConfig = (WxDefaultConfig) paramMap.get("defaultConfig");
  221. throw new CommonException(StrUtil.emptyToDefault(defaultConfig.getLowValueTip(), errorMessage));
  222. }
  223. throw new CommonException(errorMessage);
  224. }
  225. }
  226. /**
  227. * 配置相关信息
  228. *
  229. * @param ytDyzUser
  230. * @param paramMap
  231. */
  232. protected void setExtInfo(YtDyzUser ytDyzUser, Map<String, Object> paramMap) {
  233. ytDyzUser.setServiceName(applicationName);
  234. }
  235. /**
  236. * 远程调用校验用户风控,需设置风控编码[riskCode],并重写该方法
  237. * @param ytDyzUser 当前用户
  238. */
  239. protected abstract Result<?> remoteCheckLoginRisk(YtDyzUser ytDyzUser);
  240. /**
  241. * 远程调用校验注册用户
  242. * @param user 参数
  243. */
  244. protected abstract Result<?> remoteCheckRegRisk(YtDyzUser user);
  245. }