@@ -3,6 +3,7 @@ package com.gxwebsoft.auto.service.impl;
import cn.hutool.core.date.DateUtil ;
import cn.hutool.core.io.FileUtil ;
import cn.hutool.core.lang.UUID ;
import cn.hutool.core.util.DesensitizedUtil ;
import cn.hutool.core.util.StrUtil ;
import cn.hutool.http.HttpRequest ;
import com.alibaba.fastjson.JSON ;
@@ -13,6 +14,7 @@ import com.gxwebsoft.auto.service.QrLoginService;
import com.gxwebsoft.common.core.config.ConfigProperties ;
import com.gxwebsoft.common.core.security.JwtSubject ;
import com.gxwebsoft.common.core.security.JwtUtil ;
import com.gxwebsoft.common.core.utils.CommonUtil ;
import com.gxwebsoft.common.core.utils.RedisUtil ;
import com.gxwebsoft.common.system.entity.User ;
import com.gxwebsoft.common.system.entity.UserOauth ;
@@ -27,8 +29,9 @@ import java.io.File;
import java.util.HashMap ;
import java.util.concurrent.TimeUnit ;
import static com.gxwebsoft.common.core.constants.RedisConstants.* ;
import static com.gxwebsoft.common.core.constants.PlatformConstants.MP_OFFICIAL ;
import static com.gxwebsoft.common.core.constants.RedisConstants.* ;
import static com.gxwebsoft.common.core.constants.WebsiteConstants.CACHE_KEY_VERIFICATION_CODE_BY_DEV_SMS ;
/**
* 扫码登录服务实现
@@ -55,66 +58,50 @@ public class QrLoginServiceImpl implements QrLoginService {
@Autowired ( required = false )
private UserOauthService userOauthService ;
private static final String QR_LOGIN_TOKEN = " QR_LOGIN_TOKEN " ;
@Override
public QrLoginGenerateResponse generateQrLoginToken ( Integer tenantId ) {
// 生成唯一的扫码登录token
String token = UUID . randomUUID ( ) . toString ( true ) ;
// 创建扫码登录数据
QrLoginData qrLoginData = new QrLoginData ( ) ;
qrLoginData . setToken ( token ) ;
qrLoginData . setStatus ( QR_LOGIN_STATUS_PENDING ) ;
qrLoginData . setTenantId ( tenantId ) ;
qrLoginData . setNeedBindPhone ( false ) ;
qrLoginData . setMessage ( " 等待微信扫码 " ) ;
qrLoginData . setCreateTime ( DateUtil . formatDateTime ( DateUtil . date ( ) ) ) ;
qrLoginData . setExpireTime ( DateUtil . formatDateTime ( DateUtil . offsetSecond ( DateUtil . date ( ) , QR_LOGIN_TOKEN_TTL . intValue ( ) ) ) ) ;
// 存储到Redis, 设置过期时间
String redisKey = QR_LOGIN_TOKEN_KEY + token ;
redisUtil . set ( redisKey , qrLoginData , QR_LOGIN_TOKEN_TTL , TimeUnit . SECONDS ) ;
log . info ( " 生成扫码登录token: {} " , token ) ;
// 构造响应对象
QrLoginGenerateResponse response = new QrLoginGenerateResponse ( ) ;
response . setToken ( token ) ;
response . setExpiresIn ( QR_LOGIN_TOKEN_TTL ) ;
// APP扫码内容
response . setQrCodeContent ( " qr-login: " + token ) ;
// 微信小程序路径
response . setMiniprogramPath ( " /pages/qr-login?token= " + token ) ;
// 生成微信小程序码
try {
String miniprogramQrCodeUrl = generateMiniprogramQrCode ( token , tenantId ) ;
String miniprogramQrCodeUrl = generateMiniprogramQrCode ( token , tenantId ) ;
response . setMiniprogramQrCodeUrl ( miniprogramQrCodeUrl ) ;
} catch ( Exception e ) {
log . warn ( " 生成微信小程序码失败: {} " , e . getMessage ( ) ) ;
// 小程序码生成失败不影响整体功能,继续返回其他信息
}
// 生成微信扫码登录 H5 页面 URL
try {
String appId = wxService . getOfficialAppId ( tenantId ) ;
// 优先使用专门的微信扫码配置,否则使用文件服务器地址
String baseUrl = configProperties . getWechatScanUrl ( ) ;
if ( StrUtil . isBlank ( baseUrl ) ) {
baseUrl = configProperties . getFileServer ( ) ;
baseUrl = " https://websopy.websoft.top " ;
}
if ( StrUtil . isBlank ( baseUrl ) ) {
baseUrl = " https://server.websoft.top " ;
}
// 微信扫码后跳转的 H5 确认页面
String wechatScanUrl = baseUrl + " /wx-scan?token= " + token ;
response . setWechatScanUrl ( wechatScanUrl ) ;
response . setWechatAppId ( appId ) ;
log . info ( " 生成微信扫码登录URL: {} " , wechatScanUrl ) ;
response . setWechatQrCodeUrl ( generateOfficialQrCodeUrl ( token , tenantId ) ) ;
log . info ( " 生成公众号扫码登录URL: {} " , wechatScanUrl ) ;
} catch ( Exception e ) {
log . warn ( " 生成微信 扫码URL失败: {} " , e . getMessage ( ) ) ;
// 不影响整体功能
log . warn ( " 生成公众号 扫码URL失败: {} " , e . getMessage ( ) ) ;
}
return response ;
@@ -123,49 +110,34 @@ public class QrLoginServiceImpl implements QrLoginService {
@Override
public QrLoginStatusResponse checkQrLoginStatus ( String token ) {
if ( StrUtil . isBlank ( token ) ) {
return new QrLoginStatusResponse ( QR_LOGIN_STATUS_EXPIRED , null , null , 0L , null ) ;
return buildExpiredResponse ( ) ;
}
String redisKey = QR_LOGIN_TOKEN_KEY + token ;
QrLoginData qrLoginData = redisUtil . get ( redisKey , QrLoginData . class ) ;
if ( qrLoginData = = null ) {
return new QrLoginStatusResponse ( QR_LOGIN_STATUS_EXPIRED , null , null , 0L , null ) ;
return buildExpiredResponse ( ) ;
}
// 检查是否过期
if ( DateUtil . date ( ) . after ( DateUtil . parseDateTime ( qrLoginData . getExpireTime ( ) ) ) ) {
// 删除过期的token
if ( StrUtil . isBlank ( qrLoginData . getExpireTime ( ) ) | | DateUtil . date ( ) . after ( DateUtil . parseDateTime ( qrLoginData . getExpireTime ( ) ) ) ) {
redisUtil . delete ( redisKey ) ;
return new QrLoginStatusResponse ( QR_LOGIN_STATUS_EXPIRED , null , null , 0L , null ) ;
return buildExpiredResponse ( ) ;
}
// 计算剩余过期时间
long expiresIn = ( DateUtil . parseDateTime ( qrLoginData . getExpireTime ( ) ) . getTime ( ) - DateUtil . date ( ) . getTime ( ) ) / 1000 ;
long expiresIn = Math . max ( 0L ,
( DateUtil . parseDateTime ( qrLoginData . getExpireTime ( ) ) . getTime ( ) - DateUtil . date ( ) . getTime ( ) ) / 1000 ) ;
QrLoginStatusResponse response = new Q rLoginStatusResponse ( ) ;
response . setStatus ( qrLoginData . getStatus ( ) ) ;
response . setExpiresIn ( expiresIn ) ;
respons e . s etTenantId ( qrLoginData . getTenant Id ( ) ) ;
// 如果已确认, 返回token和用户信息
if ( QR_LOGIN_STATUS_CONFIRMED . equals ( qrLoginData . getStatus ( ) ) ) {
response . setAccessToken ( qrLoginData . getAccessToken ( ) ) ;
// 获取用户信息
if ( qrLoginData . getUserId ( ) ! = null ) {
User user = userService . getAllByUserId ( " " + qrLoginData . getUserId ( ) ) ;
if ( QR_LOGIN_STATUS_CONFIRMED . equals ( q rLoginData . getStatus ( ) )
& & StrUtil . isBlank ( qrLoginData . getAccessToken ( ) )
& & qrLoginData . getUserId ( ) ! = null ) {
User user = userServic e . g etAllByUserId ( String . valueOf ( qrLoginData . getUser Id ( ) ) ) ;
if ( user ! = null ) {
// 清除敏感信息
user . setPassword ( null ) ;
response . setUserInfo ( user ) ;
qrLoginData . setAccessToken ( buildAccessToken ( user ) ) ;
redisUtil . set ( redisKey , qrLoginData , Math . max ( expiresIn , 120L ) , TimeUnit . SECONDS ) ;
}
}
// 确认后删除token, 防止重复使用
// redisUtil.delete(redisKey);
}
return response ;
return buildStatusResponse ( qrLoginData , expiresIn ) ;
}
@Override
@@ -179,47 +151,35 @@ public class QrLoginServiceImpl implements QrLoginService {
String redisKey = QR_LOGIN_TOKEN_KEY + token ;
QrLoginData qrLoginData = redisUtil . get ( redisKey , QrLoginData . class ) ;
if ( qrLoginData = = null ) {
throw new RuntimeException ( " 扫码登录token不存在或已过期 " ) ;
}
// 检查是否过期
if ( DateUtil . date ( ) . after ( DateUtil . parseDateTime ( qrLoginData . getExpireTime ( ) ) ) ) {
if ( StrUtil . isBlank ( qrLoginData . getExpireTime ( ) ) | | DateUtil . date ( ) . after ( DateUtil . parseDateTime ( qrLoginData . getExpireTime ( ) ) ) ) {
redisUtil . delete ( redisKey ) ;
throw new RuntimeException ( " 扫码登录token已过期 " ) ;
}
// 获取用户信息
User user = userService . getAllByUserId ( String . valueOf ( userId ) ) ;
if ( user = = null ) {
throw new RuntimeException ( " 用户不存在 " ) ;
}
// 检查用户状态
if ( user . getStatus ( ) ! = null & & user . getStatus ( ) ! = 0 ) {
throw new RuntimeException ( " 用户已被冻结 " ) ;
}
// 生成JWT token
JwtSubject jwtSubject = new JwtSubject ( user . getUsername ( ) , user . getTenantId ( ) ) ;
String accessToken = JwtUtil . buildToken ( jwtSubject , configProperties . getTokenExpireTime ( ) , configProperties . getTokenKey ( ) ) ;
// 更新扫码登录数据
String accessToken = buildAccessToken ( user ) ;
qrLoginData . setStatus ( QR_LOGIN_STATUS_CONFIRMED ) ;
qrLoginData . setUserId ( userId ) ;
qrLoginData . setUsername ( user . getUsername ( ) ) ;
qrLoginData . setAccessToken ( accessToken ) ;
qrLoginData . setTenantId ( user . getTenantId ( ) ) ;
// 更新Redis中的数据
redisUtil . set ( redisKey , qrLoginData , 60L , TimeUnit . SECONDS ) ; // 给前端60秒时间获取token
qrLoginData . setNeedBindPhone ( false ) ;
qrLoginData . setMessage ( " 登录成功 " ) ;
redisUtil . set ( redisKey , qrLoginData , 120L , TimeUnit . SECONDS ) ;
log . info ( " 用户 {} 确认扫码登录, token: {} " , user . getUsername ( ) , token ) ;
// 清除敏感信息
user . setPassword ( null ) ;
return new QrLoginStatusResponse ( QR_LOGIN_STATUS_CONFIRMED , accessToken , user , 60L , user . getTenantId ( ) ) ;
return buildStatusResponse ( qrLoginData , 120L ) ;
}
@Override
@@ -230,25 +190,21 @@ public class QrLoginServiceImpl implements QrLoginService {
String redisKey = QR_LOGIN_TOKEN_KEY + token ;
QrLoginData qrLoginData = redisUtil . get ( redisKey , QrLoginData . class ) ;
if ( qrLoginData = = null ) {
return false ;
}
// 检查是否过期
if ( DateUtil . date ( ) . after ( DateUtil . parseDateTime ( qrLoginData . getExpireTime ( ) ) ) ) {
if ( StrUtil . isBlank ( qrLoginData . getExpireTime ( ) ) | | DateUtil . date ( ) . after ( DateUtil . parseDateTime ( qrLoginData . getExpireTime ( ) ) ) ) {
redisUtil . delete ( redisKey ) ;
return false ;
}
// 只有pending状态才能更新为scanned
if ( QR_LOGIN_STATUS_PENDING . equals ( qrLoginData . getStatus ( ) ) ) {
qrLoginData . setStatus ( QR_LOGIN_STATUS_SCANNED ) ;
// 计算剩余过期时间
long remainingSeconds = ( DateUtil . parseDateTime ( qrLoginData . getExpireTime ( ) ) . getTime ( ) - DateUtil . date ( ) . getTime ( ) ) / 1000 ;
qrLoginData . setMessage ( " 已识别扫码,等待公众号回调 " ) ;
long remainingSeconds = Math . max ( 1L ,
( DateUtil . parseDateTime ( qrLoginData . getExpireTime ( ) ) . getTime ( ) - DateUtil . date ( ) . getTime ( ) ) / 1000 ) ;
redisUtil . set ( redisKey , qrLoginData , remainingSeconds , TimeUnit . SECONDS ) ;
log . info ( " 扫码登录token {} 状态更新为已扫码 " , token ) ;
return true ;
}
@@ -256,12 +212,82 @@ public class QrLoginServiceImpl implements QrLoginService {
return false ;
}
@Override
public QrLoginStatusResponse bindPhone ( QrLoginBindPhoneRequest request ) {
if ( request = = null | | StrUtil . isBlank ( request . getToken ( ) ) | | StrUtil . isBlank ( request . getPhone ( ) ) | | StrUtil . isBlank ( request . getCode ( ) ) ) {
throw new RuntimeException ( " 参数不能为空 " ) ;
}
if ( ! CommonUtil . isValidPhoneNumber ( request . getPhone ( ) ) ) {
throw new RuntimeException ( " 请输入有效的手机号码 " ) ;
}
String redisKey = QR_LOGIN_TOKEN_KEY + request . getToken ( ) ;
QrLoginData qrLoginData = redisUtil . get ( redisKey , QrLoginData . class ) ;
if ( qrLoginData = = null ) {
throw new RuntimeException ( " 二维码已过期,请刷新后重试 " ) ;
}
if ( StrUtil . isBlank ( qrLoginData . getExpireTime ( ) ) | | DateUtil . date ( ) . after ( DateUtil . parseDateTime ( qrLoginData . getExpireTime ( ) ) ) ) {
redisUtil . delete ( redisKey ) ;
throw new RuntimeException ( " 二维码已过期,请刷新后重试 " ) ;
}
if ( ! QR_LOGIN_STATUS_BIND_PHONE . equals ( qrLoginData . getStatus ( ) ) & & ! Boolean . TRUE . equals ( qrLoginData . getNeedBindPhone ( ) ) ) {
throw new RuntimeException ( " 当前二维码无需绑定手机号 " ) ;
}
if ( qrLoginData . getUserId ( ) = = null ) {
throw new RuntimeException ( " 绑定账号不存在,请重新扫码 " ) ;
}
String codeKey = " code: " + request . getPhone ( ) ;
String smsCode = redisUtil . get ( codeKey ) ;
String devCode = redisUtil . get ( CACHE_KEY_VERIFICATION_CODE_BY_DEV_SMS ) ;
if ( StrUtil . isBlank ( smsCode ) & & StrUtil . isBlank ( devCode ) ) {
throw new RuntimeException ( " 验证码已过期,请重新获取 " ) ;
}
if ( ! StrUtil . equals ( request . getCode ( ) , smsCode ) & & ! StrUtil . equals ( request . getCode ( ) , devCode ) ) {
throw new RuntimeException ( " 验证码不正确 " ) ;
}
User user = userService . getAllByUserId ( String . valueOf ( qrLoginData . getUserId ( ) ) ) ;
if ( user = = null ) {
throw new RuntimeException ( " 用户不存在 " ) ;
}
if ( user . getStatus ( ) ! = null & & user . getStatus ( ) ! = 0 ) {
throw new RuntimeException ( " 账号已被冻结 " ) ;
}
User existed = userService . getByPhone ( request . getPhone ( ) ) ;
if ( existed ! = null & & ! existed . getUserId ( ) . equals ( user . getUserId ( ) ) ) {
throw new RuntimeException ( " 该手机号已绑定其他账号 " ) ;
}
user . setPhone ( request . getPhone ( ) ) ;
if ( StrUtil . isBlank ( user . getNickname ( ) ) | | " 微信公众号用户 " . equals ( user . getNickname ( ) ) ) {
user . setNickname ( DesensitizedUtil . mobilePhone ( request . getPhone ( ) ) ) ;
}
if ( StrUtil . isBlank ( user . getUsername ( ) ) | | user . getUsername ( ) . startsWith ( " wxoff_ " ) ) {
user . setUsername ( request . getPhone ( ) ) ;
}
userService . updateUser ( user ) ;
redisUtil . delete ( codeKey ) ;
String accessToken = buildAccessToken ( user ) ;
qrLoginData . setStatus ( QR_LOGIN_STATUS_CONFIRMED ) ;
qrLoginData . setUserId ( user . getUserId ( ) ) ;
qrLoginData . setUsername ( user . getUsername ( ) ) ;
qrLoginData . setTenantId ( user . getTenantId ( ) ) ;
qrLoginData . setAccessToken ( accessToken ) ;
qrLoginData . setNeedBindPhone ( false ) ;
qrLoginData . setMessage ( " 手机号绑定成功,正在登录 " ) ;
redisUtil . set ( redisKey , qrLoginData , 120L , TimeUnit . SECONDS ) ;
return buildStatusResponse ( qrLoginData , 120L ) ;
}
/**
* 生成微信小程序码
*/
private String generateMiniprogramQrCode ( String token , Integer tenantId ) {
try {
// 使用公共的 WxService 获取 AccessToken
String accessToken = wxService . getAccessToken ( tenantId ) ;
if ( StrUtil . isBlank ( accessToken ) ) {
throw new RuntimeException ( " 获取微信AccessToken失败 " ) ;
@@ -270,19 +296,16 @@ public class QrLoginServiceImpl implements QrLoginService {
String apiUrl = " https://api.weixin.qq.com/wxa/getwxacode?access_token= " + accessToken ;
HashMap < String , Object > params = new HashMap < > ( ) ;
params . put ( " path " , " /pages/qr-login?token= " + token ) ;
params . put ( " width " , 430 ) ; // 二维码宽度, 默认430px
params . put ( " width " , 430 ) ;
// 调用微信API生成小程序码
byte [ ] qrCodeBytes = HttpRequest . post ( apiUrl )
. body ( JSON . toJSONString ( params ) )
. execute ( ) . bodyBytes ( ) ;
// 保存文件
String fileName = " qr-login- " + token + " .png " ;
String uploadPath = getUploadPath ( ) ;
String filePath = uploadPath + " qrcode/ " + fileName ;
// 确保目录存在
File dir = new File ( uploadPath + " qrcode/ " ) ;
if ( ! dir . exists ( ) ) {
dir . mkdirs ( ) ;
@@ -290,18 +313,48 @@ public class QrLoginServiceImpl implements QrLoginService {
File file = FileUtil . writeBytes ( qrCodeBytes , filePath ) ;
if ( file ! = null & & file . exists ( ) ) {
// 返回可访问的URL
return configProperties . getFileServer ( ) + " /qrcode/ " + fileName ;
} else {
throw new RuntimeException ( " 保存小程序码文件失败 " ) ;
}
throw new RuntimeException ( " 保存小程序码文件失败 " ) ;
} catch ( Exception e ) {
log . error ( " 生成微信小程序码失败: {} " , e . getMessage ( ) , e ) ;
throw new RuntimeException ( " 生成微信小程序码失败: " + e . getMessage ( ) ) ;
}
}
/**
* 生成公众号带参数二维码
*/
private String generateOfficialQrCodeUrl ( String token , Integer tenantId ) {
try {
String accessToken = wxService . getOfficialAccessToken ( tenantId ) ;
JSONObject scene = new JSONObject ( ) ;
scene . put ( " scene_str " , token ) ;
JSONObject actionInfo = new JSONObject ( ) ;
actionInfo . put ( " scene " , scene ) ;
JSONObject params = new JSONObject ( ) ;
params . put ( " action_name " , " QR_STR_SCENE " ) ;
params . put ( " expire_seconds " , QR_LOGIN_TOKEN_TTL . intValue ( ) ) ;
params . put ( " action_info " , actionInfo ) ;
String response = HttpRequest . post ( " https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token= " + accessToken )
. body ( params . toJSONString ( ) )
. timeout ( 10000 )
. execute ( )
. body ( ) ;
JSONObject result = JSON . parseObject ( response ) ;
String ticket = result . getString ( " ticket " ) ;
if ( StrUtil . isBlank ( ticket ) ) {
throw new RuntimeException ( " 生成公众号二维码失败: " + response ) ;
}
return " https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket= "
+ java . net . URLEncoder . encode ( ticket , java . nio . charset . StandardCharsets . UTF_8 ) ;
} catch ( Exception e ) {
log . error ( " 生成公众号二维码失败: {} " , e . getMessage ( ) , e ) ;
throw new RuntimeException ( " 生成公众号二维码失败: " + e . getMessage ( ) ) ;
}
}
/**
* 获取文件上传路径
@@ -320,6 +373,38 @@ public class QrLoginServiceImpl implements QrLoginService {
return uploadPath ;
}
private String buildAccessToken ( User user ) {
JwtSubject jwtSubject = new JwtSubject ( user . getUsername ( ) , user . getTenantId ( ) ) ;
return JwtUtil . buildToken ( jwtSubject , configProperties . getTokenExpireTime ( ) , configProperties . getTokenKey ( ) ) ;
}
private QrLoginStatusResponse buildExpiredResponse ( ) {
QrLoginStatusResponse response = new QrLoginStatusResponse ( QR_LOGIN_STATUS_EXPIRED , null , null , 0L , null ) ;
response . setNeedBindPhone ( false ) ;
response . setMessage ( " 二维码已过期,请刷新后重试 " ) ;
return response ;
}
private QrLoginStatusResponse buildStatusResponse ( QrLoginData qrLoginData , Long expiresIn ) {
QrLoginStatusResponse response = new QrLoginStatusResponse ( ) ;
response . setStatus ( qrLoginData . getStatus ( ) ) ;
response . setAccessToken ( qrLoginData . getAccessToken ( ) ) ;
response . setExpiresIn ( expiresIn ) ;
response . setTenantId ( qrLoginData . getTenantId ( ) ) ;
response . setNeedBindPhone ( Boolean . TRUE . equals ( qrLoginData . getNeedBindPhone ( ) )
| | QR_LOGIN_STATUS_BIND_PHONE . equals ( qrLoginData . getStatus ( ) ) ) ;
response . setMessage ( qrLoginData . getMessage ( ) ) ;
if ( qrLoginData . getUserId ( ) ! = null ) {
User user = userService . getAllByUserId ( String . valueOf ( qrLoginData . getUserId ( ) ) ) ;
if ( user ! = null ) {
user . setPassword ( null ) ;
response . setUserInfo ( user ) ;
}
}
return response ;
}
@Override
public WechatScanResponse wechatScanConfirm ( WechatScanRequest request ) {
String token = request . getToken ( ) ;
@@ -329,13 +414,10 @@ public class QrLoginServiceImpl implements QrLoginService {
String redisKey = QR_LOGIN_TOKEN_KEY + token ;
QrLoginData qrLoginData = redisUtil . get ( redisKey , QrLoginData . class ) ;
if ( qrLoginData = = null ) {
return WechatScanResponse . notBound ( " 二维码已过期,请刷新重试 " ) ;
}
// 检查是否过期
if ( DateUtil . date ( ) . after ( DateUtil . parseDateTime ( qrLoginData . getExpireTime ( ) ) ) ) {
if ( StrUtil . isBlank ( qrLoginData . getExpireTime ( ) ) | | DateUtil . date ( ) . after ( DateUtil . parseDateTime ( qrLoginData . getExpireTime ( ) ) ) ) {
redisUtil . delete ( redisKey ) ;
return WechatScanResponse . notBound ( " 二维码已过期,请刷新重试 " ) ;
}
@@ -344,7 +426,6 @@ public class QrLoginServiceImpl implements QrLoginService {
String openId = request . getOpenId ( ) ;
Integer tenantId = qrLoginData . getTenantId ( ) ;
// 如果没有直接传 unionId, 但有 code, 需要通过 code 获取
if ( StrUtil . isBlank ( unionId ) & & StrUtil . isNotBlank ( request . getCode ( ) ) ) {
try {
JSONObject userAccessToken = wxService . getOfficialUserAccessToken ( request . getCode ( ) , tenantId ) ;
@@ -362,8 +443,6 @@ public class QrLoginServiceImpl implements QrLoginService {
}
User user = null ;
// 优先通过 unionId 查找用户
if ( StrUtil . isNotBlank ( unionId ) ) {
user = userService . getOne ( new LambdaQueryWrapper < User > ( )
. eq ( User : : getUnionid , unionId )
@@ -372,9 +451,7 @@ public class QrLoginServiceImpl implements QrLoginService {
log . info ( " 通过 unionId {} 查找用户: {} " , unionId , user ! = null ? user . getUsername ( ) : " 未找到 " ) ;
}
// 如果通过 unionId 没找到,尝试通过 openId 查找
if ( user = = null & & StrUtil . isNotBlank ( openId ) ) {
// 尝试从 sys_user 表的 openid 字段查找
user = userService . getOne ( new LambdaQueryWrapper < User > ( )
. eq ( User : : getOpenid , openId )
. eq ( User : : getDeleted , 0 )
@@ -382,7 +459,6 @@ public class QrLoginServiceImpl implements QrLoginService {
log . info ( " 通过 openId {} 查找用户: {} " , openId , user ! = null ? user . getUsername ( ) : " 未找到 " ) ;
}
// 如果还没找到,尝试从 sys_user_oauth 表查找
if ( user = = null & & ( StrUtil . isNotBlank ( unionId ) | | StrUtil . isNotBlank ( openId ) ) ) {
try {
LambdaQueryWrapper < UserOauth > wrapper = new LambdaQueryWrapper < > ( ) ;
@@ -410,30 +486,21 @@ public class QrLoginServiceImpl implements QrLoginService {
if ( user = = null ) {
return WechatScanResponse . notBound ( " 该微信未绑定平台账号,请先在平台注册并绑定微信 " ) ;
}
// 检查用户状态
if ( user . getStatus ( ) ! = null & & user . getStatus ( ) ! = 0 ) {
return WechatScanResponse . notBound ( " 账号已被冻结 " ) ;
}
// 生成 JWT token
JwtSubject jwtSubject = new JwtSubject ( user . getUsername ( ) , user . getTenantId ( ) ) ;
String accessToken = JwtUtil . buildToken ( jwtSubject , configProperties . getTokenExpireTime ( ) , configProperties . getTokenKey ( ) ) ;
// 更新扫码登录数据
String accessToken = buildAccessToken ( user ) ;
qrLoginData . setStatus ( QR_LOGIN_STATUS_CONFIRMED ) ;
qrLoginData . setUserId ( user . getUserId ( ) ) ;
qrLoginData . setUsername ( user . getUsername ( ) ) ;
qrLoginData . setAccessToken ( accessToken ) ;
qrLoginData . setTenantId ( user . getTenantId ( ) ) ;
// 更新Redis中的数据
redisUtil . set ( redisKey , qrLoginData , 60L , TimeUnit . SECONDS ) ;
qrLoginData . setNeedBindPhone ( false ) ;
qrLoginData . setMessage ( " 登录成功 " ) ;
redisUtil . set ( redisKey , qrLoginData , 120L , TimeUnit . SECONDS ) ;
log . info ( " 微信扫码登录成功,用户 {} 确认扫码登录, token: {} " , user . getUsername ( ) , token ) ;
// 清除敏感信息
user . setPassword ( null ) ;
return WechatScanResponse . success ( accessToken , user , user . getTenantId ( ) ) ;
}
}