package com.ytpm.handle;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.ytpm.agent.enums.UserStatusEnum;
import com.ytpm.app.enums.LoginType;
import com.ytpm.app.model.YtDyzLoginRecord;
import com.ytpm.app.model.YtDyzUser;
import com.ytpm.app.param.LoginParam;
import com.ytpm.app.view.WxDefaultConfig;
import com.ytpm.general.Result;
import com.ytpm.util.IPUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Map;
/**
*
登陆模板
* 兼容多登陆模式及风控校验
* 需重写方法:
* 1.登陆参数校验 validateParams
* 2.根据设备及渠道ID查询用户 queryUserByDeviceAndDitch
* 3.获取登陆默认配置 getLoginConfig
* 4.根据登陆参数获取系统用户 queryDyzUserByParam
* 5.用户新注册逻辑 registryUser
* 6.已注册用户处理逻辑 deadWithUserCrud
* 7.登陆记录保存 saveLoginRecord
* 8.远程调用风控 remoteCheckLoginRisk
* 9.远程调用风控 remoteCheckRegRisk
*
*
* 回调方法:
* 1.用户注册时回调 beforeRegistryUser
* 2.用户登陆时回调 beforeDeadWithUserCrud
*
*
* 可选重写方法:
* 1.第三方登陆调用处理及参数传递 setThirdPartyLoginInfo
* 2.登陆成功后调用风控服务校验 ytRiskValidate
* 3.登陆用户信息配置额外信息 setExtInfo
*
*
* @author lih
* @date 2025/9/4
*/
public abstract class AbstractLoginService {
@Value("${risk.config.banned.tips}")
private String tips;
protected abstract LoginType getLoginType();
/**
* 登陆逻辑处理
* @param loginParam 登陆参数
* @param request request
* @return YtDyzUser
*/
public final YtDyzUser loginHandle(LoginParam loginParam, HttpServletRequest request) {
loginParam.setLoginIp(IPUtil.getClientIp(request));
// 获取默认配置
WxDefaultConfig defaultConfig = getLoginConfig(loginParam.getAppType());
if (Objects.isNull(defaultConfig)) {
throw new CommonException(StrUtil.format("{}登录失败,未找到相应配置!", getLoginType().getTypeName()));
}
loginParam.setAppId(defaultConfig.getPlatformAppId());
// 参数校验
validateParams(loginParam, request);
// 获取第三方登陆信息 如微信授权码、微信登陆后授权信息
Map paramMap = setThirdPartyLoginInfo(loginParam, defaultConfig, request);
YtDyzUser ytDyzUser;
if (getLoginType() == LoginType.VISITOR) {
// 游客模式
paramMap.put("defaultConfig", defaultConfig);
ytDyzUser = visitorLoginHandle(loginParam, paramMap);
} else {
ytDyzUser = clientLoginHandle(loginParam, paramMap);
}
// 配置额外信息
setExtInfo(ytDyzUser, paramMap);
// 添加用户登录记录
addLoginRecord(loginParam,ytDyzUser.getUserId());
// 调用风控服务校验默认风控配置
ytRiskValidate(ytDyzUser);
return ytDyzUser;
}
/**
* 登陆参数校验
*/
protected abstract void validateParams(LoginParam loginParam, HttpServletRequest request);
/**
* 微信端/IOS端登陆
*/
private YtDyzUser clientLoginHandle(LoginParam loginParam, Map paramMap) {
YtDyzUser ytDyzUser;
List ytDyzUsers = queryDyzUserByParam(loginParam, paramMap);
if (CollectionUtils.isEmpty(ytDyzUsers)) {
beforeRegistryUser(loginParam, paramMap);
ytDyzUser = new YtDyzUser();
registryUser(loginParam, ytDyzUser, paramMap);
} else {
ytDyzUser = ytDyzUsers.get(0);
beforeDeadWithUserCrud(loginParam, ytDyzUser, paramMap);
deadWithUserCrud(loginParam, ytDyzUser, paramMap);
}
return ytDyzUser;
}
/**
* 游客模式登录
*/
private YtDyzUser visitorLoginHandle(LoginParam loginParam, Map paramMap) {
// 唯一性判断
// 1.查询设备ID不存在记录 则根据设备id+渠道id注册用户
// 2.查询设备ID存在记录 则根据渠道ID控制唯一性,同步出路风控记录
YtDyzUser ytDyzUser = null;
List ytDyzUsers = queryDyzUserByParam(loginParam, paramMap);
if(CollUtil.isEmpty(ytDyzUsers)) {
//注册后回调
beforeRegistryUser(loginParam, paramMap);
ytDyzUser = new YtDyzUser();
registryUser(loginParam, ytDyzUser, paramMap);
} else {
// 查询当前设备当前渠道是否存在该用户
ytDyzUser = queryUserByDeviceAndDitch(loginParam.getDeviceId(), loginParam.getDitchId());
if(ytDyzUser == null) {
ytDyzUser = new YtDyzUser();
registryUser(loginParam, ytDyzUser, paramMap);
}
//当前渠道已有用户,校验用户是否处于风控中 & 更新用户信息
beforeDeadWithUserCrud(loginParam, ytDyzUser, paramMap);
//如果当前登录是本日第一次登录则登录天数+1
deadWithUserCrud(loginParam, ytDyzUser, paramMap);
}
// 保存广告信息
WxDefaultConfig defaultConfig = (WxDefaultConfig) paramMap.get("defaultConfig");
saveVisitorAdRecord(ytDyzUser, loginParam, defaultConfig);
return ytDyzUser;
}
// 游客登陆时保存传递记录
protected void saveVisitorAdRecord(YtDyzUser ytDyzUser, LoginParam loginParam, WxDefaultConfig defaultConfig) {
}
/**
* 根据设备及渠道ID查询用户
*/
protected abstract YtDyzUser queryUserByDeviceAndDitch(String deviceId, Long ditchId);
/**
* 第三方登陆调用处理及参数传递
*/
protected Map setThirdPartyLoginInfo(LoginParam loginParam, WxDefaultConfig defaultConfig,
HttpServletRequest request) {
Map map = new HashMap<>();
return map;
}
/**
* 获取登陆默认配置
*/
protected abstract WxDefaultConfig getLoginConfig(Integer appType);
/**
* 根据登陆配置信息 查询系统用户记录
* @param loginParam 登陆参数
* @param thirdPartyLoginInfo 第三方登陆西悉尼
*/
protected abstract List queryDyzUserByParam(LoginParam loginParam, Map thirdPartyLoginInfo);
// 注册用户处理器回调
protected void beforeRegistryUser(LoginParam loginParam, Map paramMap){
}
// 用户注册逻辑
protected abstract YtDyzUser registryUser(LoginParam loginParam,YtDyzUser user, Map paramMap);
// 已注册用户处理前回调
protected void beforeDeadWithUserCrud(LoginParam loginParam, YtDyzUser ytDyzUser, Map paramMap){
//当前渠道已有用户,校验用户是否处于风控中 & 更新用户信息
if(ytDyzUser != null && !ytDyzUser.getUserStatus().equals(UserStatusEnum.NORMAL.getCode())){
throw new CommonException(getTipsMsg());
}
}
private String getTipsMsg(){
String[] split = tips.split(",");
return split[RandomUtil.randomInt(split.length)];
}
// 已注册用户处理逻辑
protected abstract void deadWithUserCrud(LoginParam loginParam, YtDyzUser old, Map paramMap);
private void addLoginRecord(LoginParam param, String userId) {
YtDyzLoginRecord loginRecord = new YtDyzLoginRecord();
loginRecord.setRecordId(IdUtil.fastSimpleUUID());
loginRecord.setUserId(userId);
loginRecord.setLoginTime(new Date());
loginRecord.setDeviceBrand(param.getBrand());
loginRecord.setDeviceModel(param.getModel());
loginRecord.setLoginIp(param.getLoginIp());
loginRecord.setOperator(param.getIpOperator());
loginRecord.setIpAddr(param.getIpLocation());
loginRecord.setPhoneJson(param.getPhoneJson());
saveLoginRecord(loginRecord);
}
/**
* 保存登陆记录实现
*/
protected abstract void saveLoginRecord(YtDyzLoginRecord loginRecord);
/**
* 调用风控服务校验默认风控配置
*/
protected void ytRiskValidate(YtDyzUser ytDyzUser) {
Result> result = remoteCheckLoginRisk(ytDyzUser);
if (result == null || result.getCode() != 200) {
throw new CommonException(result == null ? "feign invoke Fail!" : result.getMessage());
}
}
/**
* 配置相关信息
*
* @param ytDyzUser
* @param paramMap
*/
protected void setExtInfo(YtDyzUser ytDyzUser, Map paramMap) {
}
/**
* 远程调用校验用户风控,需设置风控编码[riskCode],并重写该方法
* @param ytDyzUser 当前用户
*/
protected abstract Result> remoteCheckLoginRisk(YtDyzUser ytDyzUser);
/**
* 远程调用校验注册用户
* @param user 参数
*/
protected abstract Result> remoteCheckRegRisk(YtDyzUser user);
}