refactor(qrLogin): 简化二维码生成逻辑,移除文件生成和请求

- 二维码内容改为自定义协议,前端生成base64二维码
- 不再生成微信小程序码图片文件,删除相关生成方法
- 不再生成公众号带参数二维码URL,前端使用扫码跳转URL
- 扫码跳转URL改为配置值,提供默认域名降级处理
- 删除了生成文件和请求微信API的多余代码和相关依赖
- 保持miniprogramQrCodeUrl和wechatQrCodeUrl为空,由前端自动处理
This commit is contained in:
2026-04-07 17:33:52 +08:00
parent fa09d9dc23
commit 345afab954

View File

@@ -1,12 +1,9 @@
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;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gxwebsoft.auto.dto.*;
@@ -26,9 +23,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import static com.gxwebsoft.common.core.constants.PlatformConstants.MP_OFFICIAL;
@@ -84,31 +79,30 @@ public class QrLoginServiceImpl implements QrLoginService {
QrLoginGenerateResponse response = new QrLoginGenerateResponse();
response.setToken(token);
response.setExpiresIn(QR_LOGIN_TOKEN_TTL);
response.setQrCodeContent("qr-login:" + token);
// 二维码内容使用自定义协议前端据此生成base64二维码
response.setQrCodeContent("websopy://login?token=" + token);
// 小程序路径(用于小程序扫码直接打开)
response.setMiniprogramPath("/pages/qr-login?token=" + token);
// 扫码跳转URL前端生成二维码时使用此URL
try {
String miniprogramQrCodeUrl = generateMiniprogramQrCode(token, tenantId);
response.setMiniprogramQrCodeUrl(miniprogramQrCodeUrl);
} catch (Exception e) {
log.warn("生成微信小程序码失败: {}", e.getMessage());
}
try {
String appId = wxService.getOfficialAppId(tenantId);
String baseUrl = configProperties.getWechatScanUrl();
if (StrUtil.isBlank(baseUrl)) {
baseUrl = "https://websopy.websoft.top";
}
String wechatScanUrl = baseUrl + "/wx-scan?token=" + token;
response.setWechatScanUrl(wechatScanUrl);
response.setWechatAppId(appId);
response.setWechatQrCodeUrl(generateOfficialQrCodeUrl(token, tenantId));
log.info("生成公众号扫码登录URL: {}", wechatScanUrl);
log.info("扫码跳转URL: {}", wechatScanUrl);
} catch (Exception e) {
log.warn("生成公众号扫码URL失败: {}", e.getMessage());
log.warn("获取扫码跳转URL失败: {}", e.getMessage());
// 降级:使用默认域名
response.setWechatScanUrl("https://websopy.websoft.top/wx-scan?token=" + token);
}
// 不再生成小程序码图片文件改为前端通过qrCodeContent生成base64二维码
// 不再生成公众号带参数二维码URL前端使用wechatScanUrl生成二维码
// miniprogramQrCodeUrl 和 wechatQrCodeUrl 保持null前端自动使用本地生成
return response;
}
@@ -317,96 +311,6 @@ public class QrLoginServiceImpl implements QrLoginService {
return buildStatusResponse(qrLoginData, 120L);
}
/**
* 生成微信小程序码
*/
private String generateMiniprogramQrCode(String token, Integer tenantId) {
try {
String accessToken = wxService.getAccessToken(tenantId);
if (StrUtil.isBlank(accessToken)) {
throw new RuntimeException("获取微信AccessToken失败");
}
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);
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();
}
File file = FileUtil.writeBytes(qrCodeBytes, filePath);
if (file != null && file.exists()) {
return configProperties.getFileServer() + "/qrcode/" + fileName;
}
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());
}
}
/**
* 获取文件上传路径
*/
private String getUploadPath() {
String uploadPath = configProperties.getUploadPath();
if (StrUtil.isBlank(uploadPath)) {
uploadPath = configProperties.getLocalUploadPath();
}
if (StrUtil.isBlank(uploadPath)) {
uploadPath = "/tmp/uploads/";
}
if (!uploadPath.endsWith("/")) {
uploadPath += "/";
}
return uploadPath;
}
private String buildAccessToken(User user) {
JwtSubject jwtSubject = new JwtSubject(user.getUsername(), user.getTenantId());
return JwtUtil.buildToken(jwtSubject, configProperties.getTokenExpireTime(), configProperties.getTokenKey());