修改小程序登录逻辑
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
package com.ruoyi.cms.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class WechatAuthVO {
|
||||||
|
private String openid;
|
||||||
|
private String unionid;
|
||||||
|
private String sessionKey;
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import com.ruoyi.common.core.domain.entity.AppUserShow;
|
|||||||
import com.ruoyi.common.core.domain.entity.MyChart;
|
import com.ruoyi.common.core.domain.entity.MyChart;
|
||||||
import com.ruoyi.common.core.domain.entity.AppUser;
|
import com.ruoyi.common.core.domain.entity.AppUser;
|
||||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* APP用户Mapper接口
|
* APP用户Mapper接口
|
||||||
@@ -26,15 +27,15 @@ public interface AppUserMapper extends BaseMapper<AppUser>
|
|||||||
|
|
||||||
List<AppUser> selectByJobId(Long jobId);
|
List<AppUser> selectByJobId(Long jobId);
|
||||||
|
|
||||||
AppUser selectByOpenid(String openid);
|
AppUser selectByOpenid(@Param("openid")String openid, @Param("userType") String userType);
|
||||||
|
|
||||||
int insertSysUserRole(Map<String,Object> map);
|
int insertSysUserRole(Map<String,Object> map);
|
||||||
|
|
||||||
int insertSysUser(SysUser sysUser);
|
int insertSysUser(SysUser sysUser);
|
||||||
|
|
||||||
MyChart getMyTj(Long userId);
|
MyChart getMyTj(@Param("userId") Long userId);
|
||||||
|
|
||||||
SysUser selectSysUserIdcard(String idCard);
|
SysUser selectSysUserIdcard(@Param("idCard") String idCard);
|
||||||
|
|
||||||
List<AppUserShow> selectUserApplyList(AppUser appUser);
|
List<AppUserShow> selectUserApplyList(AppUser appUser);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,11 @@ public interface IAppUserService
|
|||||||
|
|
||||||
public AppUser getPhone(String phone);
|
public AppUser getPhone(String phone);
|
||||||
|
|
||||||
AppUser selectByOpenid(String openid);
|
public AppUser getPhoneAndNoRole(String phone);
|
||||||
|
|
||||||
|
public AppUser getPhoneAndUserType(String phone,String userType);
|
||||||
|
|
||||||
|
AppUser selectByOpenid(String openid,String userType);
|
||||||
|
|
||||||
public AppUser registerAppUser(RegisterBody registerBody);
|
public AppUser registerAppUser(RegisterBody registerBody);
|
||||||
|
|
||||||
|
|||||||
@@ -185,8 +185,20 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper,AppUser> imple
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AppUser selectByOpenid(String openid) {
|
public AppUser getPhoneAndNoRole(String phone) {
|
||||||
return appUserMapper.selectByOpenid(openid);
|
return appUserMapper.selectOne(new LambdaQueryWrapper<AppUser>()
|
||||||
|
.eq(AppUser::getPhone, phone).eq(AppUser::getDelFlag,"0").isNull(AppUser::getIsCompanyUser).orderByDesc(AppUser::getUpdateTime).last("LIMIT 1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AppUser getPhoneAndUserType(String phone,String userType) {
|
||||||
|
return appUserMapper.selectOne(new LambdaQueryWrapper<AppUser>()
|
||||||
|
.eq(AppUser::getPhone, phone).eq(AppUser::getIsCompanyUser,userType).eq(AppUser::getDelFlag,"0").orderByDesc(AppUser::getUpdateTime).last("LIMIT 1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AppUser selectByOpenid(String openid,String userType) {
|
||||||
|
return appUserMapper.selectByOpenid(openid,userType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectByOpenid" resultType="com.ruoyi.common.core.domain.entity.AppUser">
|
<select id="selectByOpenid" resultType="com.ruoyi.common.core.domain.entity.AppUser">
|
||||||
<include refid="selectAppUserVo"/> WHERE DEL_FLAG = '0' and openid=#{openid} LIMIT 1
|
<include refid="selectAppUserVo"/> WHERE DEL_FLAG = '0' and openid=#{openid} and is_company_user=#{userType} LIMIT 1
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<insert id="insertSysUserRole" parameterType="java.util.Map">
|
<insert id="insertSysUserRole" parameterType="java.util.Map">
|
||||||
|
|||||||
@@ -0,0 +1,211 @@
|
|||||||
|
package com.ruoyi.common.core.redis;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JDK 1.8 兼容版分布式锁工具类(基于 Redis)
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class DistributedLockUtil {
|
||||||
|
@Autowired
|
||||||
|
private RedisCache redisCache;
|
||||||
|
|
||||||
|
// 锁默认配置
|
||||||
|
private static final long DEFAULT_EXPIRE_SECONDS = 30;
|
||||||
|
private static final long DEFAULT_ACQUIRE_TIMEOUT_SECONDS = 5;
|
||||||
|
private static final long RENEW_INTERVAL_SECONDS = DEFAULT_EXPIRE_SECONDS / 3;
|
||||||
|
|
||||||
|
// 续期线程池
|
||||||
|
private final ScheduledExecutorService renewExecutor = Executors.newScheduledThreadPool(
|
||||||
|
Runtime.getRuntime().availableProcessors(),
|
||||||
|
new ThreadFactory() {
|
||||||
|
private final AtomicBoolean init = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable r) {
|
||||||
|
Thread thread = new Thread(r, "distributed-lock-renewer");
|
||||||
|
thread.setDaemon(true);
|
||||||
|
if (init.compareAndSet(false, true)) {
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
renewExecutor.shutdown();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 释放锁 Lua 脚本(原子操作)
|
||||||
|
private static final String RELEASE_LOCK_LUA_SCRIPT =
|
||||||
|
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
|
||||||
|
" return redis.call('del', KEYS[1]) " +
|
||||||
|
"else " +
|
||||||
|
" return 0 " +
|
||||||
|
"end";
|
||||||
|
private final DefaultRedisScript<Long> releaseScript = new DefaultRedisScript<>();
|
||||||
|
|
||||||
|
// 初始化 Lua 脚本
|
||||||
|
{
|
||||||
|
releaseScript.setScriptText(RELEASE_LOCK_LUA_SCRIPT);
|
||||||
|
releaseScript.setResultType(Long.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取锁(带自动续期)
|
||||||
|
*/
|
||||||
|
public String acquireLockWithRenewal(String lockKey) {
|
||||||
|
return acquireLockWithRenewal(lockKey, DEFAULT_EXPIRE_SECONDS, DEFAULT_ACQUIRE_TIMEOUT_SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义参数获取锁
|
||||||
|
*/
|
||||||
|
public String acquireLockWithRenewal(String lockKey, long expireSeconds, long acquireTimeoutSeconds) {
|
||||||
|
String identifier = UUID.randomUUID().toString();
|
||||||
|
long endTime = System.currentTimeMillis() + acquireTimeoutSeconds * 1000;
|
||||||
|
|
||||||
|
while (System.currentTimeMillis() < endTime) {
|
||||||
|
boolean locked = tryLockOnce(lockKey, identifier, expireSeconds);
|
||||||
|
if (locked) {
|
||||||
|
startRenewal(lockKey, identifier, expireSeconds);
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 指数退避重试
|
||||||
|
try {
|
||||||
|
long sleepMs = calculateBackoffSleep(System.currentTimeMillis() - (endTime - acquireTimeoutSeconds * 1000));
|
||||||
|
Thread.sleep(sleepMs);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原子释放锁
|
||||||
|
*/
|
||||||
|
public boolean releaseLockSafely(String lockKey, String identifier) {
|
||||||
|
if (identifier == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Long result = (Long) redisCache.redisTemplate.execute(
|
||||||
|
releaseScript,
|
||||||
|
Collections.singletonList(lockKey),
|
||||||
|
identifier
|
||||||
|
);
|
||||||
|
return result != null && result > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试获取一次锁
|
||||||
|
*/
|
||||||
|
private boolean tryLockOnce(String lockKey, String identifier, long expireSeconds) {
|
||||||
|
try {
|
||||||
|
if (!redisCache.hasKey(lockKey)) {
|
||||||
|
redisCache.setCacheObject(lockKey, identifier, (int) expireSeconds, TimeUnit.SECONDS);
|
||||||
|
String storedId = redisCache.getCacheObject(lockKey);
|
||||||
|
return identifier.equals(storedId);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动锁自动续期
|
||||||
|
*/
|
||||||
|
private void startRenewal(final String lockKey, final String identifier, final long expireSeconds) {
|
||||||
|
final AtomicReference<ScheduledFuture<?>> futureRef = new AtomicReference<>();
|
||||||
|
Runnable renewalTask = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
String storedId = redisCache.getCacheObject(lockKey);
|
||||||
|
if (identifier.equals(storedId)) {
|
||||||
|
redisCache.expire(lockKey, expireSeconds);
|
||||||
|
} else {
|
||||||
|
cancelFuture();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
cancelFuture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelFuture() {
|
||||||
|
ScheduledFuture<?> future = futureRef.get();
|
||||||
|
if (future != null && !future.isCancelled()) {
|
||||||
|
future.cancel(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ScheduledFuture<?> future = renewExecutor.scheduleAtFixedRate(
|
||||||
|
renewalTask,
|
||||||
|
RENEW_INTERVAL_SECONDS,
|
||||||
|
RENEW_INTERVAL_SECONDS,
|
||||||
|
TimeUnit.SECONDS
|
||||||
|
);
|
||||||
|
futureRef.set(future);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指数退避算法(计算重试间隔)
|
||||||
|
*/
|
||||||
|
private long calculateBackoffSleep(long elapsedMs) {
|
||||||
|
int retryCount = (int) (elapsedMs / 100);
|
||||||
|
long sleepMs = 100L * (1 << Math.min(retryCount, 10));
|
||||||
|
return Math.min(sleepMs, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动释放锁工具(支持 try-with-resources)
|
||||||
|
*/
|
||||||
|
public static class AutoReleaseLock implements AutoCloseable {
|
||||||
|
private final DistributedLockUtil lockUtil;
|
||||||
|
private final String lockKey;
|
||||||
|
private final String identifier;
|
||||||
|
|
||||||
|
public AutoReleaseLock(DistributedLockUtil lockUtil, String lockKey, String identifier) {
|
||||||
|
this.lockUtil = lockUtil;
|
||||||
|
this.lockKey = lockKey;
|
||||||
|
this.identifier = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLocked() {
|
||||||
|
return identifier != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
if (isLocked()) {
|
||||||
|
lockUtil.releaseLockSafely(lockKey, identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 简化锁使用
|
||||||
|
*/
|
||||||
|
public AutoReleaseLock tryLock(String lockKey) {
|
||||||
|
String identifier = acquireLockWithRenewal(lockKey);
|
||||||
|
return new AutoReleaseLock(this, lockKey, identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import javax.annotation.Resource;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.ruoyi.cms.domain.vo.WechatAuthVO;
|
||||||
import com.ruoyi.cms.service.IAppUserService;
|
import com.ruoyi.cms.service.IAppUserService;
|
||||||
import com.ruoyi.cms.util.StringUtil;
|
import com.ruoyi.cms.util.StringUtil;
|
||||||
import com.ruoyi.cms.util.WechatUtil;
|
import com.ruoyi.cms.util.WechatUtil;
|
||||||
@@ -12,6 +13,7 @@ import com.ruoyi.common.core.domain.entity.AppUser;
|
|||||||
import com.ruoyi.common.core.domain.model.LoginBody;
|
import com.ruoyi.common.core.domain.model.LoginBody;
|
||||||
import com.ruoyi.common.core.domain.model.LoginSiteUser;
|
import com.ruoyi.common.core.domain.model.LoginSiteUser;
|
||||||
import com.ruoyi.common.core.domain.model.RegisterBody;
|
import com.ruoyi.common.core.domain.model.RegisterBody;
|
||||||
|
import com.ruoyi.common.core.redis.DistributedLockUtil;
|
||||||
import com.ruoyi.common.utils.*;
|
import com.ruoyi.common.utils.*;
|
||||||
import com.ruoyi.framework.web.exception.ParamErrorConstants;
|
import com.ruoyi.framework.web.exception.ParamErrorConstants;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -69,6 +71,9 @@ public class SysLoginService
|
|||||||
WechatUtil wechatUtil;
|
WechatUtil wechatUtil;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IAppUserService appUserService;
|
private IAppUserService appUserService;
|
||||||
|
@Autowired
|
||||||
|
private DistributedLockUtil distributedLockUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录验证
|
* 登录验证
|
||||||
*
|
*
|
||||||
@@ -258,7 +263,7 @@ public class SysLoginService
|
|||||||
return AjaxResult.error("微信授权失败");
|
return AjaxResult.error("微信授权失败");
|
||||||
}
|
}
|
||||||
//验证是否登录过
|
//验证是否登录过
|
||||||
AppUser existingUser=appUserService.selectByOpenid(openid);
|
AppUser existingUser=appUserService.selectByOpenid(openid,dto.getUserType());
|
||||||
if(existingUser!=null){
|
if(existingUser!=null){
|
||||||
if(StringUtils.isEmpty(existingUser.getIsCompanyUser())){
|
if(StringUtils.isEmpty(existingUser.getIsCompanyUser())){
|
||||||
updateAppUserCommon(existingUser,openid,unionid,dto.getUserType());
|
updateAppUserCommon(existingUser,openid,unionid,dto.getUserType());
|
||||||
@@ -316,44 +321,37 @@ public class SysLoginService
|
|||||||
* 小程序登录主逻辑
|
* 小程序登录主逻辑
|
||||||
*/
|
*/
|
||||||
public AjaxResult appLoginNew(LoginBody dto) {
|
public AjaxResult appLoginNew(LoginBody dto) {
|
||||||
AjaxResult validateResult = validateLoginParam(dto, false);
|
//1.验证基础参数
|
||||||
|
AjaxResult validateResult = validateBaseParam(dto);
|
||||||
if (validateResult != null) {
|
if (validateResult != null) {
|
||||||
return validateResult;
|
return validateResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
JSONObject sessionInfo = wechatUtil.code2Session(dto.getCode());
|
//2. 微信授权获取OpenID/UnionID/SessionKey
|
||||||
String openid = sessionInfo.getString("openid");
|
WechatAuthVO wechatAuthVO = getWechatAuthInfo(dto.getCode());
|
||||||
String unionid = sessionInfo.getString("unionid");
|
if (wechatAuthVO == null) {
|
||||||
String sessionKey = sessionInfo.getString("session_key");
|
|
||||||
|
|
||||||
if (openid == null) {
|
|
||||||
return AjaxResult.error("微信授权失败");
|
return AjaxResult.error("微信授权失败");
|
||||||
}
|
}
|
||||||
|
String openid = wechatAuthVO.getOpenid();
|
||||||
|
String unionid = wechatAuthVO.getUnionid();
|
||||||
|
String sessionKey = wechatAuthVO.getSessionKey();
|
||||||
|
|
||||||
AppUser existingUser = appUserService.selectByOpenid(openid);
|
String userType = dto.getUserType();
|
||||||
|
//3. 优先匹配「OpenID+角色」的老用户
|
||||||
|
AppUser existingUser = appUserService.selectByOpenid(openid,userType);
|
||||||
if (existingUser != null) {
|
if (existingUser != null) {
|
||||||
return handleExistingUser(existingUser, dto.getUserType());
|
return handleExistingUser(existingUser, userType);
|
||||||
}
|
}
|
||||||
|
|
||||||
validateResult = validateLoginParam(dto, true);
|
// 4. 解密获取手机号(含二次校验)
|
||||||
if (validateResult != null) {
|
String phone = decryptPhone(dto, sessionKey);
|
||||||
return validateResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONObject phoneInfo = wechatUtil.decryptPhoneNumber(dto.getEncryptedData(), sessionKey, dto.getIv());
|
|
||||||
String phone = phoneInfo.getString("phoneNumber");
|
|
||||||
|
|
||||||
if (phone == null) {
|
if (phone == null) {
|
||||||
return AjaxResult.error("获取手机号失败");
|
return AjaxResult.error("获取手机号失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
AppUser phoneUser = appUserService.getPhone(phone);
|
// 5. 处理用户匹配与注册(核心逻辑拆分到独立方法)
|
||||||
if (phoneUser != null) {
|
return handleUserMatchAndRegister(openid, unionid, phone, userType);
|
||||||
return handlePhoneBoundUser(phoneUser, openid, unionid, dto.getUserType());
|
|
||||||
} else {
|
|
||||||
return handleNewUser(openid, unionid, phone, dto.getUserType());
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.println("登录失败:" + e.getMessage());
|
System.err.println("登录失败:" + e.getMessage());
|
||||||
return AjaxResult.error("登录失败,请稍后重试");
|
return AjaxResult.error("登录失败,请稍后重试");
|
||||||
@@ -361,9 +359,11 @@ public class SysLoginService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 参数校验方法(仅返回错误信息,补充userType校验)
|
* 1-基础参数校验(原validateLoginParam false场景)
|
||||||
|
* @param dto
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
private AjaxResult validateLoginParam(LoginBody dto, boolean needDecryptPhone) {
|
private AjaxResult validateBaseParam(LoginBody dto) {
|
||||||
if (dto == null) {
|
if (dto == null) {
|
||||||
return AjaxResult.error(ParamErrorConstants.PARAM_NULL_MSG);
|
return AjaxResult.error(ParamErrorConstants.PARAM_NULL_MSG);
|
||||||
}
|
}
|
||||||
@@ -376,17 +376,134 @@ public class SysLoginService
|
|||||||
!StringUtil.IS_JOB_REQUEST_USER.equals(userType)) {
|
!StringUtil.IS_JOB_REQUEST_USER.equals(userType)) {
|
||||||
return AjaxResult.error(ParamErrorConstants.USER_TYPE_INVALID_MSG);
|
return AjaxResult.error(ParamErrorConstants.USER_TYPE_INVALID_MSG);
|
||||||
}
|
}
|
||||||
if (needDecryptPhone) {
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2-微信授权信息获取(封装code2Session逻辑)
|
||||||
|
* @param code
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private WechatAuthVO getWechatAuthInfo(String code) {
|
||||||
|
JSONObject sessionInfo = wechatUtil.code2Session(code);
|
||||||
|
if (sessionInfo == null || sessionInfo.getString("openid") == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
WechatAuthVO authVO = new WechatAuthVO();
|
||||||
|
authVO.setOpenid(sessionInfo.getString("openid"));
|
||||||
|
authVO.setUnionid(StringUtils.isBlank(sessionInfo.getString("unionid")) ? "" : sessionInfo.getString("unionid"));
|
||||||
|
authVO.setSessionKey(sessionInfo.getString("session_key"));
|
||||||
|
return authVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 3-手机号解密(含二次参数校验)
|
||||||
|
* @param dto
|
||||||
|
* @param sessionKey
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String decryptPhone(LoginBody dto, String sessionKey) {
|
||||||
|
// 二次校验(解密相关参数)
|
||||||
|
AjaxResult validateResult = validateDecryptParam(dto);
|
||||||
|
if (validateResult != null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 解密手机号
|
||||||
|
JSONObject phoneInfo = wechatUtil.decryptPhoneNumber(dto.getEncryptedData(), sessionKey, dto.getIv());
|
||||||
|
String phone = phoneInfo.getString("phoneNumber");
|
||||||
|
if (phone == null || phone.trim().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return phone.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 4-解密参数校验(原validateLoginParam true场景)
|
||||||
|
* @param dto
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private AjaxResult validateDecryptParam(LoginBody dto) {
|
||||||
if (StringUtils.isEmpty(dto.getEncryptedData())) {
|
if (StringUtils.isEmpty(dto.getEncryptedData())) {
|
||||||
return AjaxResult.error(ParamErrorConstants.ENCRYPTED_DATA_EMPTY_MSG);
|
return AjaxResult.error(ParamErrorConstants.ENCRYPTED_DATA_EMPTY_MSG);
|
||||||
}
|
}
|
||||||
if (StringUtils.isEmpty(dto.getIv())) {
|
if (StringUtils.isEmpty(dto.getIv())) {
|
||||||
return AjaxResult.error(ParamErrorConstants.IV_EMPTY_MSG);
|
return AjaxResult.error(ParamErrorConstants.IV_EMPTY_MSG);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 5-用户匹配与注册(含锁逻辑、无角色数据处理)
|
||||||
|
* @param openid
|
||||||
|
* @param unionid
|
||||||
|
* @param phone
|
||||||
|
* @param userType
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private AjaxResult handleUserMatchAndRegister(String openid, String unionid, String phone, String userType) {
|
||||||
|
// 匹配「手机号+角色」的用户
|
||||||
|
AppUser phoneRoleUser = appUserService.getPhoneAndUserType(phone, userType);
|
||||||
|
if (phoneRoleUser != null) {
|
||||||
|
return handlePhoneBoundUser(phoneRoleUser, openid, unionid, userType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匹配无角色历史数据
|
||||||
|
AppUser noRoleUser = appUserService.getPhoneAndNoRole(phone);
|
||||||
|
if (noRoleUser != null) {
|
||||||
|
return handleNoRoleUserBinding(openid, unionid, phone, userType, noRoleUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全新用户注册
|
||||||
|
return handleNewUserRegistration(openid, unionid, phone, userType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 6-无角色用户绑定(含分布式锁)
|
||||||
|
* @param openid
|
||||||
|
* @param unionid
|
||||||
|
* @param phone
|
||||||
|
* @param userType
|
||||||
|
* @param noRoleUser
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private AjaxResult handleNoRoleUserBinding(String openid, String unionid, String phone, String userType, AppUser noRoleUser) {
|
||||||
|
String lockKey = "login_no_role_bind_" + phone + "_" + userType;
|
||||||
|
try (DistributedLockUtil.AutoReleaseLock lock = distributedLockUtil.tryLock(lockKey)) {
|
||||||
|
if (!lock.isLocked()) {
|
||||||
|
return AjaxResult.error("登录请求过于频繁,请稍后重试");
|
||||||
|
}
|
||||||
|
// 双重检查
|
||||||
|
AppUser doubleCheck = appUserService.getPhoneAndUserType(phone, userType);
|
||||||
|
if (doubleCheck != null) {
|
||||||
|
return handlePhoneBoundUser(doubleCheck, openid, unionid, userType);
|
||||||
|
}
|
||||||
|
return handlePhoneBoundUser(noRoleUser, openid, unionid, userType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 7-新用户注册(含分布式锁)
|
||||||
|
* @param openid
|
||||||
|
* @param unionid
|
||||||
|
* @param phone
|
||||||
|
* @param userType
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private AjaxResult handleNewUserRegistration(String openid, String unionid, String phone, String userType) {
|
||||||
|
String createLockKey = "login_create_" + phone + "_" + userType;
|
||||||
|
try (DistributedLockUtil.AutoReleaseLock lock = distributedLockUtil.tryLock(createLockKey)) {
|
||||||
|
if (!lock.isLocked()) {
|
||||||
|
return AjaxResult.error("登录请求过于频繁,请稍后重试");
|
||||||
|
}
|
||||||
|
// 双重检查
|
||||||
|
AppUser checkNew = appUserService.getPhoneAndUserType(phone, userType);
|
||||||
|
if (checkNew != null) {
|
||||||
|
return handlePhoneBoundUser(checkNew, openid, unionid, userType);
|
||||||
|
}
|
||||||
|
return handleNewUser(openid, unionid, phone, userType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理老用户登录(日志用println)
|
* 处理老用户登录(日志用println)
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user