微信小程序登录修改
This commit is contained in:
@@ -103,6 +103,10 @@ INSERT INTO config.tb_sys_config (
|
||||
('CFG-0703', 'cfg_wechat_kefu_token', 'wechat.kefu.token', '回调Token', '', 'String', 'input', '消息回调的Token', NULL, NULL, 'wechat', 'mod_workcase', 30, 1, '用于验证消息回调的Token', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0704', 'cfg_wechat_kefu_aeskey', 'wechat.kefu.encodingAesKey','回调加密密钥', '', 'String', 'password', '消息回调的EncodingAESKey', NULL, NULL, 'wechat', 'mod_workcase', 40, 1, '用于解密消息回调的AES密钥', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0705', 'cfg_wechat_kefu_openkfid', 'wechat.kefu.openKfid', '客服账号ID', '', 'String', 'input', '微信客服账号的open_kfid', NULL, NULL, 'wechat', 'mod_workcase', 50, 1, '用于发送消息的客服账号ID', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0706', 'cfg_wechat_kefu_welcome', 'wechat.kefu.welcomeTemplate','欢迎语模板', '您好,您的工单已创建。\n工单编号:{workcaseId}\n问题类型:{type}\n设备:{device}\n我们将尽快为您处理。', 'String', 'textarea', '客服欢迎语消息模板', NULL, NULL, 'wechat', 'mod_workcase', 60, 1, '支持变量:{workcaseId},{type},{device},{username}', 'system', NULL, NULL, now(), NULL, NULL, false);
|
||||
('CFG-0706', 'cfg_wechat_kefu_welcome', 'wechat.kefu.welcomeTemplate','欢迎语模板', '您好,您的工单已创建。\n工单编号:{workcaseId}\n问题类型:{type}\n设备:{device}\n我们将尽快为您处理。', 'String', 'textarea', '客服欢迎语消息模板', NULL, NULL, 'wechat', 'mod_workcase', 60, 1, '支持变量:{workcaseId},{type},{device},{username}', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
|
||||
-- 微信小程序配置
|
||||
('CFG-0710', 'cfg_wechat_mp_appid', 'wechat.miniprogram.appid', '小程序AppID', 'wx3708f41b1dc31f52', 'String', 'input', '微信小程序的AppID', NULL, NULL, 'wechat', 'mod_workcase', 70, 1, '在微信公众平台获取', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0711', 'cfg_wechat_mp_appsecret', 'wechat.miniprogram.appsecret', '小程序AppSecret', '127dcc9c90dd1b66a700b52094922253', 'String', 'password', '微信小程序的AppSecret', NULL, NULL, 'wechat', 'mod_workcase', 80, 1, '在微信公众平台获取,用于获取openid和解密手机号', 'system', NULL, NULL, now(), NULL, NULL, false);
|
||||
|
||||
|
||||
|
||||
@@ -94,4 +94,30 @@ public class LoginParam implements Serializable {
|
||||
*/
|
||||
private String token;
|
||||
|
||||
// ========== 微信小程序登录相关字段 ==========
|
||||
|
||||
/**
|
||||
* 微信登录code(wx.login返回,用于换取openid和session_key)
|
||||
* @since 2026-01-09
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 手机号授权code(getPhoneNumber返回,新版API推荐使用)
|
||||
* @since 2026-01-09
|
||||
*/
|
||||
private String phoneCode;
|
||||
|
||||
/**
|
||||
* 加密数据(getPhoneNumber返回,旧版API用于解密手机号)
|
||||
* @since 2026-01-09
|
||||
*/
|
||||
private String encryptedData;
|
||||
|
||||
/**
|
||||
* 解密向量(getPhoneNumber返回,旧版API用于解密手机号)
|
||||
* @since 2026-01-09
|
||||
*/
|
||||
private String iv;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.xyzh.common.wechat.config;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 微信小程序配置
|
||||
* @author cascade
|
||||
* @since 2026-01-09
|
||||
*/
|
||||
@Data
|
||||
public class WeChatMiniProgramConfig {
|
||||
|
||||
/** 小程序AppID */
|
||||
private String appId;
|
||||
|
||||
/** 小程序AppSecret */
|
||||
private String appSecret;
|
||||
|
||||
/** 当前access_token */
|
||||
private String accessToken;
|
||||
|
||||
/** access_token过期时间(毫秒时间戳) */
|
||||
private Long accessTokenExpireTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.xyzh.common.wechat.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 微信小程序获取手机号接口返回结果
|
||||
* @author cascade
|
||||
* @since 2026-01-09
|
||||
*/
|
||||
@Data
|
||||
public class WeChatPhoneResult {
|
||||
|
||||
/** 错误码 */
|
||||
private Integer errcode;
|
||||
|
||||
/** 错误信息 */
|
||||
private String errmsg;
|
||||
|
||||
/** 手机号信息 */
|
||||
private PhoneInfo phoneInfo;
|
||||
|
||||
/**
|
||||
* 手机号信息
|
||||
*/
|
||||
@Data
|
||||
public static class PhoneInfo {
|
||||
/** 用户绑定的手机号(国外手机号会有区号) */
|
||||
private String phoneNumber;
|
||||
|
||||
/** 没有区号的手机号 */
|
||||
private String purePhoneNumber;
|
||||
|
||||
/** 区号 */
|
||||
private String countryCode;
|
||||
|
||||
/** 数据水印 */
|
||||
private Watermark watermark;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据水印
|
||||
*/
|
||||
@Data
|
||||
public static class Watermark {
|
||||
/** 小程序appid */
|
||||
private String appid;
|
||||
|
||||
/** 时间戳 */
|
||||
private Long timestamp;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.xyzh.common.wechat.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 微信小程序 code2Session 接口返回结果
|
||||
* @author cascade
|
||||
* @since 2026-01-09
|
||||
*/
|
||||
@Data
|
||||
public class WeChatSessionResult {
|
||||
|
||||
/** 用户唯一标识 */
|
||||
private String openid;
|
||||
|
||||
/** 会话密钥 */
|
||||
private String sessionKey;
|
||||
|
||||
/** 用户在开放平台的唯一标识符(需要绑定开放平台) */
|
||||
private String unionid;
|
||||
|
||||
/** 错误码 */
|
||||
private Integer errcode;
|
||||
|
||||
/** 错误信息 */
|
||||
private String errmsg;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
package org.xyzh.common.wechat.service;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.xyzh.api.system.service.SysConfigService;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.wechat.config.WeChatMiniProgramConfig;
|
||||
import org.xyzh.common.wechat.pojo.WeChatPhoneResult;
|
||||
import org.xyzh.common.wechat.pojo.WeChatSessionResult;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
|
||||
/**
|
||||
* 微信小程序服务
|
||||
* @author cascade
|
||||
* @since 2026-01-09
|
||||
*/
|
||||
@Service
|
||||
public class WeChatMiniProgramService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(WeChatMiniProgramService.class);
|
||||
|
||||
/** 微信小程序配置缓存 */
|
||||
private WeChatMiniProgramConfig config;
|
||||
|
||||
/** code2Session接口地址 */
|
||||
private static final String CODE2SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session";
|
||||
|
||||
/** 获取access_token接口地址 */
|
||||
private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
|
||||
|
||||
/** 获取手机号接口地址(新版API) */
|
||||
private static final String GET_PHONE_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber";
|
||||
|
||||
@DubboReference(version = "1.0.0", group = "system", timeout = 5000, check = false, retries = 0)
|
||||
private SysConfigService sysConfigService;
|
||||
|
||||
/**
|
||||
* 获取微信小程序配置
|
||||
*/
|
||||
public WeChatMiniProgramConfig getConfig() {
|
||||
if (config == null) {
|
||||
loadConfig();
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从系统配置加载微信小程序配置
|
||||
*/
|
||||
private synchronized void loadConfig() {
|
||||
if (config != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
config = new WeChatMiniProgramConfig();
|
||||
|
||||
try {
|
||||
// 从系统配置获取小程序AppID
|
||||
ResultDomain<String> appIdResult = sysConfigService.getConfigValue("wechat.miniprogram.appid");
|
||||
if (appIdResult.getSuccess() && appIdResult.getData() != null) {
|
||||
config.setAppId(appIdResult.getData());
|
||||
}
|
||||
|
||||
// 从系统配置获取小程序AppSecret
|
||||
ResultDomain<String> appSecretResult = sysConfigService.getConfigValue("wechat.miniprogram.appsecret");
|
||||
if (appSecretResult.getSuccess() && appSecretResult.getData() != null) {
|
||||
config.setAppSecret(appSecretResult.getData());
|
||||
}
|
||||
|
||||
logger.info("微信小程序配置加载成功, appId: {}", config.getAppId());
|
||||
} catch (Exception e) {
|
||||
logger.error("加载微信小程序配置失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新配置
|
||||
*/
|
||||
public void refreshConfig() {
|
||||
config = null;
|
||||
loadConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过code获取session信息(openid和session_key)
|
||||
* @param code wx.login返回的code
|
||||
* @return session信息
|
||||
*/
|
||||
public ResultDomain<WeChatSessionResult> code2Session(String code) {
|
||||
WeChatMiniProgramConfig cfg = getConfig();
|
||||
if (cfg == null || cfg.getAppId() == null || cfg.getAppSecret() == null) {
|
||||
return ResultDomain.failure("微信小程序配置未初始化");
|
||||
}
|
||||
|
||||
try {
|
||||
String url = String.format("%s?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
|
||||
CODE2SESSION_URL, cfg.getAppId(), cfg.getAppSecret(), code);
|
||||
|
||||
String response = httpGet(url);
|
||||
logger.debug("code2Session响应: {}", response);
|
||||
|
||||
WeChatSessionResult result = JSON.parseObject(response, WeChatSessionResult.class);
|
||||
|
||||
if (result.getErrcode() != null && result.getErrcode() != 0) {
|
||||
logger.error("code2Session失败: {} - {}", result.getErrcode(), result.getErrmsg());
|
||||
return ResultDomain.failure("获取session失败: " + result.getErrmsg());
|
||||
}
|
||||
|
||||
return ResultDomain.success("获取session成功", result);
|
||||
} catch (Exception e) {
|
||||
logger.error("code2Session异常", e);
|
||||
return ResultDomain.failure("获取session异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access_token
|
||||
* @return access_token
|
||||
*/
|
||||
public String getAccessToken() {
|
||||
WeChatMiniProgramConfig cfg = getConfig();
|
||||
if (cfg == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查缓存的token是否有效
|
||||
if (cfg.getAccessToken() != null && cfg.getAccessTokenExpireTime() != null
|
||||
&& System.currentTimeMillis() < cfg.getAccessTokenExpireTime()) {
|
||||
return cfg.getAccessToken();
|
||||
}
|
||||
|
||||
// 重新获取token
|
||||
try {
|
||||
String url = String.format("%s?grant_type=client_credential&appid=%s&secret=%s",
|
||||
ACCESS_TOKEN_URL, cfg.getAppId(), cfg.getAppSecret());
|
||||
|
||||
String response = httpGet(url);
|
||||
JSONObject json = JSON.parseObject(response);
|
||||
|
||||
if (json.containsKey("access_token")) {
|
||||
String accessToken = json.getString("access_token");
|
||||
int expiresIn = json.getIntValue("expires_in");
|
||||
|
||||
cfg.setAccessToken(accessToken);
|
||||
// 提前5分钟过期
|
||||
cfg.setAccessTokenExpireTime(System.currentTimeMillis() + (expiresIn - 300) * 1000L);
|
||||
|
||||
logger.info("获取access_token成功, 有效期: {}秒", expiresIn);
|
||||
return accessToken;
|
||||
} else {
|
||||
logger.error("获取access_token失败: {}", response);
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("获取access_token异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过phoneCode获取手机号(新版API,推荐使用)
|
||||
* @param phoneCode getPhoneNumber返回的code
|
||||
* @return 手机号信息
|
||||
*/
|
||||
public ResultDomain<WeChatPhoneResult> getPhoneNumber(String phoneCode) {
|
||||
String accessToken = getAccessToken();
|
||||
if (accessToken == null) {
|
||||
return ResultDomain.failure("获取access_token失败");
|
||||
}
|
||||
|
||||
try {
|
||||
String url = GET_PHONE_URL + "?access_token=" + accessToken;
|
||||
|
||||
JSONObject requestBody = new JSONObject();
|
||||
requestBody.put("code", phoneCode);
|
||||
|
||||
String response = httpPost(url, requestBody.toJSONString());
|
||||
logger.debug("getPhoneNumber响应: {}", response);
|
||||
|
||||
WeChatPhoneResult result = JSON.parseObject(response, WeChatPhoneResult.class);
|
||||
|
||||
if (result.getErrcode() != null && result.getErrcode() != 0) {
|
||||
logger.error("getPhoneNumber失败: {} - {}", result.getErrcode(), result.getErrmsg());
|
||||
return ResultDomain.failure("获取手机号失败: " + result.getErrmsg());
|
||||
}
|
||||
|
||||
return ResultDomain.success("获取手机号成功", result);
|
||||
} catch (Exception e) {
|
||||
logger.error("getPhoneNumber异常", e);
|
||||
return ResultDomain.failure("获取手机号异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过encryptedData和iv解密手机号(旧版API)
|
||||
* @param sessionKey 会话密钥
|
||||
* @param encryptedData 加密数据
|
||||
* @param iv 解密向量
|
||||
* @return 解密后的手机号
|
||||
*/
|
||||
public ResultDomain<String> decryptPhoneNumber(String sessionKey, String encryptedData, String iv) {
|
||||
try {
|
||||
byte[] sessionKeyBytes = Base64.getDecoder().decode(sessionKey);
|
||||
byte[] encryptedDataBytes = Base64.getDecoder().decode(encryptedData);
|
||||
byte[] ivBytes = Base64.getDecoder().decode(iv);
|
||||
|
||||
SecretKeySpec keySpec = new SecretKeySpec(sessionKeyBytes, "AES");
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
|
||||
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
|
||||
|
||||
byte[] decryptedBytes = cipher.doFinal(encryptedDataBytes);
|
||||
String decryptedData = new String(decryptedBytes, StandardCharsets.UTF_8);
|
||||
|
||||
logger.debug("解密数据: {}", decryptedData);
|
||||
|
||||
JSONObject json = JSON.parseObject(decryptedData);
|
||||
String phoneNumber = json.getString("phoneNumber");
|
||||
|
||||
if (phoneNumber == null || phoneNumber.isEmpty()) {
|
||||
phoneNumber = json.getString("purePhoneNumber");
|
||||
}
|
||||
|
||||
return ResultDomain.success("解密成功", phoneNumber);
|
||||
} catch (Exception e) {
|
||||
logger.error("解密手机号失败", e);
|
||||
return ResultDomain.failure("解密手机号失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP GET请求
|
||||
*/
|
||||
private String httpGet(String urlStr) throws Exception {
|
||||
URL url = new URL(urlStr);
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestMethod("GET");
|
||||
conn.setConnectTimeout(5000);
|
||||
conn.setReadTimeout(5000);
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
|
||||
StringBuilder response = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
return response.toString();
|
||||
} finally {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP POST请求
|
||||
*/
|
||||
private String httpPost(String urlStr, String body) throws Exception {
|
||||
URL url = new URL(urlStr);
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setConnectTimeout(5000);
|
||||
conn.setReadTimeout(5000);
|
||||
conn.setDoOutput(true);
|
||||
conn.setRequestProperty("Content-Type", "application/json");
|
||||
|
||||
try (OutputStream os = conn.getOutputStream()) {
|
||||
os.write(body.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
|
||||
StringBuilder response = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
return response.toString();
|
||||
} finally {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,6 +25,10 @@
|
||||
<groupId>org.xyzh.common</groupId>
|
||||
<artifactId>common-all</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xyzh.common</groupId>
|
||||
<artifactId>common-wechat</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xyzh.apis</groupId>
|
||||
<artifactId>api-system</artifactId>
|
||||
|
||||
@@ -8,6 +8,8 @@ import java.util.concurrent.TimeUnit;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
@@ -34,6 +36,9 @@ import org.xyzh.common.dto.sys.TbSysUserRoleDTO;
|
||||
import org.xyzh.common.dto.sys.TbSysViewDTO;
|
||||
import org.xyzh.common.utils.id.IdUtil;
|
||||
import org.xyzh.common.utils.validation.ValidationUtils;
|
||||
import org.xyzh.common.wechat.pojo.WeChatPhoneResult;
|
||||
import org.xyzh.common.wechat.pojo.WeChatSessionResult;
|
||||
import org.xyzh.common.wechat.service.WeChatMiniProgramService;
|
||||
import org.xyzh.common.auth.utils.JwtTokenUtil;
|
||||
import org.xyzh.common.redis.service.RedisService;
|
||||
|
||||
@@ -54,6 +59,8 @@ import jakarta.validation.constraints.NotNull;
|
||||
@RequestMapping("/system/guest")
|
||||
public class GuestController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GuestController.class);
|
||||
|
||||
@Autowired
|
||||
private GuestService guestService;
|
||||
|
||||
@@ -69,6 +76,9 @@ public class GuestController {
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
@Autowired
|
||||
private WeChatMiniProgramService weChatMiniProgramService;
|
||||
|
||||
|
||||
@PostMapping
|
||||
public ResultDomain<TbGuestDTO> createGuest(TbGuestDTO guest) {
|
||||
@@ -120,6 +130,63 @@ public class GuestController {
|
||||
@Operation(summary = "微信小程序用户识别登录")
|
||||
@PostMapping("/identify")
|
||||
public ResultDomain<LoginDomain> identifyUser(@RequestBody LoginParam loginParam, HttpServletRequest request) {
|
||||
logger.info("微信小程序登录请求: wechatId={}, code={}, phoneCode={}",
|
||||
loginParam.getWechatId(),
|
||||
loginParam.getCode() != null ? loginParam.getCode().substring(0, Math.min(10, loginParam.getCode().length())) + "..." : null,
|
||||
loginParam.getPhoneCode() != null ? "有" : "无");
|
||||
|
||||
// 1. 处理微信登录code,获取openid
|
||||
String openid = null;
|
||||
String sessionKey = null;
|
||||
if (loginParam.getCode() != null && !loginParam.getCode().trim().isEmpty()) {
|
||||
ResultDomain<WeChatSessionResult> sessionResult = weChatMiniProgramService.code2Session(loginParam.getCode());
|
||||
if (sessionResult.getSuccess() && sessionResult.getData() != null) {
|
||||
openid = sessionResult.getData().getOpenid();
|
||||
sessionKey = sessionResult.getData().getSessionKey();
|
||||
logger.info("获取openid成功: {}", openid);
|
||||
// 使用openid作为wechatId
|
||||
loginParam.setWechatId(openid);
|
||||
} else {
|
||||
logger.warn("获取openid失败: {}", sessionResult.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 处理手机号授权
|
||||
String phoneNumber = null;
|
||||
|
||||
// 方式1:使用phoneCode获取手机号(新版API,推荐)
|
||||
if (loginParam.getPhoneCode() != null && !loginParam.getPhoneCode().trim().isEmpty()) {
|
||||
ResultDomain<WeChatPhoneResult> phoneResult = weChatMiniProgramService.getPhoneNumber(loginParam.getPhoneCode());
|
||||
if (phoneResult.getSuccess() && phoneResult.getData() != null && phoneResult.getData().getPhoneInfo() != null) {
|
||||
phoneNumber = phoneResult.getData().getPhoneInfo().getPurePhoneNumber();
|
||||
if (phoneNumber == null) {
|
||||
phoneNumber = phoneResult.getData().getPhoneInfo().getPhoneNumber();
|
||||
}
|
||||
logger.info("通过phoneCode获取手机号成功: {}", phoneNumber);
|
||||
} else {
|
||||
logger.warn("通过phoneCode获取手机号失败: {}", phoneResult.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 方式2:使用encryptedData和iv解密手机号(旧版API)
|
||||
if (phoneNumber == null && sessionKey != null
|
||||
&& loginParam.getEncryptedData() != null && !loginParam.getEncryptedData().trim().isEmpty()
|
||||
&& loginParam.getIv() != null && !loginParam.getIv().trim().isEmpty()) {
|
||||
ResultDomain<String> decryptResult = weChatMiniProgramService.decryptPhoneNumber(
|
||||
sessionKey, loginParam.getEncryptedData(), loginParam.getIv());
|
||||
if (decryptResult.getSuccess() && decryptResult.getData() != null) {
|
||||
phoneNumber = decryptResult.getData();
|
||||
logger.info("通过解密获取手机号成功: {}", phoneNumber);
|
||||
} else {
|
||||
logger.warn("解密手机号失败: {}", decryptResult.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 设置手机号
|
||||
if (phoneNumber != null) {
|
||||
loginParam.setPhone(phoneNumber);
|
||||
}
|
||||
|
||||
// 验证参数:必须有wechatId或phone
|
||||
if ((loginParam.getWechatId() == null || loginParam.getWechatId().trim().isEmpty())
|
||||
&& (loginParam.getPhone() == null || loginParam.getPhone().trim().isEmpty())) {
|
||||
@@ -132,14 +199,15 @@ public class GuestController {
|
||||
// 从 request 中提取客户端 IP 并设置到 loginParam
|
||||
loginParam.setClientIp(getClientIP(request));
|
||||
|
||||
// 1. 尝试通过AuthService登录(员工)
|
||||
// 3. 尝试通过AuthService登录(员工)
|
||||
ResultDomain<LoginDomain> loginResult = authService.login(loginParam);
|
||||
if (loginResult.getSuccess() && loginResult.getData() != null) {
|
||||
// 登录成功,是系统员工
|
||||
logger.info("员工登录成功: userId={}", loginResult.getData().getUser().getUserId());
|
||||
return loginResult;
|
||||
}
|
||||
|
||||
// 2. 登录失败,查询/注册来客
|
||||
// 4. 登录失败,查询/注册来客
|
||||
return handleGuestLogin(loginParam);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user