refactor(wxOfficial): 优化公众号配置和access_token获取逻辑

- 增加SettingService和WxService注入,提高配置获取灵活性
- 将access_token获取方法重载,支持按租户动态读取
- 新增getOfficialToken、getOfficialEncodingAESKey、getOfficialAppId方法,从系统设置读取配置
- 解密消息时改用动态获取的token、EncodingAESKey和AppId
- 微信用户信息请求改为支持按租户获取access_token
- access_token获取失败时添加异常日志并回退到兼容逻辑
- 移除硬编码逻辑,增强配置读取的可扩展性与健壮性
This commit is contained in:
2026-04-06 21:54:14 +08:00
parent 655e6a6205
commit 97b735757d

View File

@@ -24,10 +24,12 @@ import com.gxwebsoft.common.system.entity.*;
import com.gxwebsoft.common.system.param.RoleParam; import com.gxwebsoft.common.system.param.RoleParam;
import com.gxwebsoft.common.system.param.UserParam; import com.gxwebsoft.common.system.param.UserParam;
import com.gxwebsoft.common.system.service.RoleService; import com.gxwebsoft.common.system.service.RoleService;
import com.gxwebsoft.common.system.service.SettingService;
import com.gxwebsoft.common.system.service.UserOauthService; import com.gxwebsoft.common.system.service.UserOauthService;
import com.gxwebsoft.common.system.service.UserRoleService; import com.gxwebsoft.common.system.service.UserRoleService;
import com.gxwebsoft.common.system.service.UserService; import com.gxwebsoft.common.system.service.UserService;
import com.gxwebsoft.common.system.service.UserSyncService; import com.gxwebsoft.common.system.service.UserSyncService;
import com.gxwebsoft.common.system.service.WxService;
import com.gxwebsoft.common.system.vo.WxOfficialButton; import com.gxwebsoft.common.system.vo.WxOfficialButton;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
@@ -88,6 +90,10 @@ public class WxOfficialController extends BaseController {
@Resource @Resource
private UserOauthService userOauthService; private UserOauthService userOauthService;
@Resource @Resource
private SettingService settingService;
@Resource
private WxService wxService;
@Resource
private RedisUtil redisUtil; private RedisUtil redisUtil;
@Operation(summary = "验证微信服务器") @Operation(summary = "验证微信服务器")
@@ -98,7 +104,7 @@ public class WxOfficialController extends BaseController {
if (tenantId == null) { if (tenantId == null) {
return null; return null;
} }
String token = TOKEN; String token = getOfficialToken();
String[] array = new String[]{token, timestamp, nonce}; String[] array = new String[]{token, timestamp, nonce};
// 将token、timestamp、nonce三个参数进行字典序排序 // 将token、timestamp、nonce三个参数进行字典序排序
Arrays.sort(array); Arrays.sort(array);
@@ -133,7 +139,7 @@ public class WxOfficialController extends BaseController {
// 如果有加密参数,进行解密 // 如果有加密参数,进行解密
if (StrUtil.isNotBlank(msg_signature) && StrUtil.isNotBlank(xmlData) && xmlData.contains("Encrypt")) { if (StrUtil.isNotBlank(msg_signature) && StrUtil.isNotBlank(xmlData) && xmlData.contains("Encrypt")) {
try { try {
WXBizJsonMsgCrypt crypt = new WXBizJsonMsgCrypt(TOKEN, ENCODING_AES_KEY, ""); WXBizJsonMsgCrypt crypt = new WXBizJsonMsgCrypt(getOfficialToken(), getOfficialEncodingAESKey(), getOfficialAppId(tenantId));
xmlData = crypt.DecryptMsg(msg_signature, timestamp, nonce, xmlData); xmlData = crypt.DecryptMsg(msg_signature, timestamp, nonce, xmlData);
System.out.println("解密后xmlData = " + xmlData); System.out.println("解密后xmlData = " + xmlData);
} catch (Exception e) { } catch (Exception e) {
@@ -189,7 +195,7 @@ public class WxOfficialController extends BaseController {
// 获取用户信息 // 获取用户信息
if (StrUtil.isNotBlank(openId)) { if (StrUtil.isNotBlank(openId)) {
// 获取用户基本信息(UnionID机制) // 获取用户基本信息(UnionID机制)
final String userStr = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + getAccessToken() + "&openid=" + openId + "&lang=zh_CN"); final String userStr = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + getAccessToken(tenantId) + "&openid=" + openId + "&lang=zh_CN");
final JSONObject jsonObject = JSONObject.parseObject(userStr); final JSONObject jsonObject = JSONObject.parseObject(userStr);
final String unionid = jsonObject.getString("unionid"); final String unionid = jsonObject.getString("unionid");
final String subscribe = jsonObject.getString("subscribe"); final String subscribe = jsonObject.getString("subscribe");
@@ -451,30 +457,65 @@ public class WxOfficialController extends BaseController {
// 调用接口凭证 // 调用接口凭证
private String getAccessToken() { private String getAccessToken() {
return getAccessToken(null);
}
private String getAccessToken(Integer tenantId) {
try {
return wxService.getOfficialAccessToken(tenantId);
} catch (Exception ex) {
log.warn("从系统设置获取公众号access_token失败回退到兼容逻辑: {}", ex.getMessage());
}
String key = MP_OFFICIAL.concat(":access_token:5"); String key = MP_OFFICIAL.concat(":access_token:5");
// 从缓存获取access_token
String value = redisUtil.get(key); String value = redisUtil.get(key);
if (value != null) { if (value != null) {
// 解析access_token
JSONObject response = JSON.parseObject(value); JSONObject response = JSON.parseObject(value);
return response.getString("access_token"); return response.getString("access_token");
} }
// 微信获取凭证接口https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
String apiUrl = "https://api.weixin.qq.com/cgi-bin/token"; String apiUrl = "https://api.weixin.qq.com/cgi-bin/token";
// 组装url参数
String url = apiUrl.concat("?grant_type=client_credential").concat("&appid=").concat(appid).concat("&secret=").concat(secret); String url = apiUrl.concat("?grant_type=client_credential").concat("&appid=").concat(appid).concat("&secret=").concat(secret);
// 执行get请求
String result = HttpUtil.get(url); String result = HttpUtil.get(url);
// 解析access_token
JSONObject response = JSON.parseObject(result); JSONObject response = JSON.parseObject(result);
if (response.getString("access_token") != null) { if (response.getString("access_token") != null) {
// 存入缓存
redisUtil.set(key, result, 7000L, TimeUnit.SECONDS); redisUtil.set(key, result, 7000L, TimeUnit.SECONDS);
return response.getString("access_token"); return response.getString("access_token");
} }
return null; return null;
} }
private String getOfficialToken() {
try {
JSONObject config = settingService.getBySettingKey("wx-official");
String token = config.getString("token");
return StrUtil.isNotBlank(token) ? token : TOKEN;
} catch (Exception ex) {
log.warn("读取公众号token配置失败回退到硬编码值: {}", ex.getMessage());
return TOKEN;
}
}
private String getOfficialEncodingAESKey() {
try {
JSONObject config = settingService.getBySettingKey("wx-official");
String encodingAESKey = config.getString("encodingAESKey");
return StrUtil.isNotBlank(encodingAESKey) ? encodingAESKey : ENCODING_AES_KEY;
} catch (Exception ex) {
log.warn("读取公众号EncodingAESKey配置失败回退到硬编码值: {}", ex.getMessage());
return ENCODING_AES_KEY;
}
}
private String getOfficialAppId(Integer tenantId) {
try {
return wxService.getOfficialAppId(tenantId);
} catch (Exception ex) {
log.warn("读取公众号AppId配置失败回退到硬编码值: {}", ex.getMessage());
return appid;
}
}
@Operation(summary = "创建公众号菜单接口") @Operation(summary = "创建公众号菜单接口")
@PostMapping("/createMenu") @PostMapping("/createMenu")
public ApiResult<?> createMenu() { public ApiResult<?> createMenu() {