feat(wechat): Add WeChat official account token and encryption key configuration
All checks were successful
continuous-integration/drone/push Build is passing

- Add token and encodingAESKey fields to NotificationTemplatesConfig interface
- Add UI form inputs for WeChat token and EncodingAESKey in system config page
- Add configuration constants SaTokenKey and SaEncodingAesKeyKey to SystemConfigService
- Update WeChatEventController to fetch token from database instead of hardcoded value
- Make CheckSignature method async and retrieve token from ISystemConfigService
- Update GetNotificationTemplates to include token and encodingAESKey from config
- Update SetNotificationTemplates to persist token and encodingAESKey to database
- Update mini app manifest with new appid
- Enables dynamic WeChat server configuration without code changes
This commit is contained in:
zpc 2026-03-29 20:03:12 +08:00
parent 600eeead70
commit 4af5ae8065
5 changed files with 61 additions and 9 deletions

View File

@ -189,6 +189,8 @@ export function setRealNamePrice(price: number) {
*
*/
export interface NotificationTemplatesConfig {
token?: string
encodingAESKey?: string
unlockTemplateId?: string
favoriteTemplateId?: string
messageTemplateId?: string

View File

@ -313,6 +313,24 @@
style="margin-bottom: 24px;"
/>
<el-form-item label="服务号Token">
<el-input
v-model="templateForm.token"
placeholder="微信公众平台配置的Token"
clearable
/>
<div class="template-tip">在微信公众平台 基本配置 服务器配置中设置的Token需保持一致</div>
</el-form-item>
<el-form-item label="EncodingAESKey">
<el-input
v-model="templateForm.encodingAESKey"
placeholder="消息加解密密钥43位字符"
clearable
/>
<div class="template-tip">微信公众平台 基本配置 服务器配置中的消息加解密密钥明文模式可不填</div>
</el-form-item>
<el-form-item label="解锁通知模板ID">
<el-input
v-model="templateForm.unlockTemplateId"
@ -417,6 +435,8 @@ const agreementForm = ref({
})
const templateForm = ref({
token: '',
encodingAESKey: '',
unlockTemplateId: '',
favoriteTemplateId: '',
messageTemplateId: '',
@ -695,6 +715,8 @@ const loadNotificationTemplates = async () => {
try {
const res = await getNotificationTemplates()
if (res) {
templateForm.value.token = res.token || ''
templateForm.value.encodingAESKey = res.encodingAESKey || ''
templateForm.value.unlockTemplateId = res.unlockTemplateId || ''
templateForm.value.favoriteTemplateId = res.favoriteTemplateId || ''
templateForm.value.messageTemplateId = res.messageTemplateId || ''
@ -709,6 +731,8 @@ const saveNotificationTemplates = async () => {
savingTemplates.value = true
try {
await setNotificationTemplates({
token: templateForm.value.token || undefined,
encodingAESKey: templateForm.value.encodingAESKey || undefined,
unlockTemplateId: templateForm.value.unlockTemplateId || undefined,
favoriteTemplateId: templateForm.value.favoriteTemplateId || undefined,
messageTemplateId: templateForm.value.messageTemplateId || undefined,

View File

@ -1,6 +1,6 @@
{
"name" : "相宜亲家",
"appid" : "__UNI__39EAECC",
"appid" : "__UNI__85044B9",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",

View File

@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Linq;
using XiangYi.Application.Interfaces;
using XiangYi.Core.Entities.Biz;
using XiangYi.Core.Interfaces;
@ -19,30 +20,30 @@ public class WeChatEventController : ControllerBase
private readonly IRepository<User> _userRepository;
private readonly ILogger<WeChatEventController> _logger;
private readonly IConfiguration _configuration;
// 服务号Token需要在微信公众平台配置
private const string Token = "xiangyi2024";
private readonly ISystemConfigService _configService;
public WeChatEventController(
IRepository<User> userRepository,
ILogger<WeChatEventController> logger,
IConfiguration configuration)
IConfiguration configuration,
ISystemConfigService configService)
{
_userRepository = userRepository;
_logger = logger;
_configuration = configuration;
_configService = configService;
}
/// <summary>
/// 微信服务器验证GET请求
/// </summary>
[HttpGet]
public IActionResult Verify(string signature, string timestamp, string nonce, string echostr)
public async Task<IActionResult> Verify(string signature, string timestamp, string nonce, string echostr)
{
_logger.LogInformation("收到微信服务器验证请求: signature={Signature}, timestamp={Timestamp}, nonce={Nonce}",
signature, timestamp, nonce);
if (CheckSignature(signature, timestamp, nonce))
if (await CheckSignatureAsync(signature, timestamp, nonce))
{
_logger.LogInformation("微信服务器验证成功");
return Content(echostr);
@ -169,9 +170,16 @@ public class WeChatEventController : ControllerBase
/// <summary>
/// 验证微信签名
/// </summary>
private bool CheckSignature(string signature, string timestamp, string nonce)
private async Task<bool> CheckSignatureAsync(string signature, string timestamp, string nonce)
{
var arr = new[] { Token, timestamp, nonce };
var token = await _configService.GetConfigValueAsync("sa_token");
if (string.IsNullOrEmpty(token))
{
_logger.LogWarning("服务号Token未配置");
return false;
}
var arr = new[] { token, timestamp, nonce };
Array.Sort(arr);
var str = string.Join("", arr);

View File

@ -98,6 +98,8 @@ public class SystemConfigService : ISystemConfigService
/// </summary>
public const decimal DefaultRealNamePrice = 88m;
public const string SaTokenKey = "sa_token";
public const string SaEncodingAesKeyKey = "sa_encoding_aes_key";
public const string SaUnlockTemplateIdKey = "sa_unlock_template_id";
public const string SaFavoriteTemplateIdKey = "sa_favorite_template_id";
public const string SaMessageTemplateIdKey = "sa_message_template_id";
@ -355,6 +357,8 @@ public class SystemConfigService : ISystemConfigService
{
return new NotificationTemplatesDto
{
Token = await GetConfigValueAsync(SaTokenKey),
EncodingAESKey = await GetConfigValueAsync(SaEncodingAesKeyKey),
UnlockTemplateId = await GetConfigValueAsync(SaUnlockTemplateIdKey),
FavoriteTemplateId = await GetConfigValueAsync(SaFavoriteTemplateIdKey),
MessageTemplateId = await GetConfigValueAsync(SaMessageTemplateIdKey),
@ -367,6 +371,10 @@ public class SystemConfigService : ISystemConfigService
{
try
{
if (!string.IsNullOrEmpty(templates.Token))
await SetConfigValueAsync(SaTokenKey, templates.Token, "服务号验证Token");
if (!string.IsNullOrEmpty(templates.EncodingAESKey))
await SetConfigValueAsync(SaEncodingAesKeyKey, templates.EncodingAESKey, "服务号消息加解密密钥");
if (!string.IsNullOrEmpty(templates.UnlockTemplateId))
await SetConfigValueAsync(SaUnlockTemplateIdKey, templates.UnlockTemplateId, "服务号解锁通知模板ID");
if (!string.IsNullOrEmpty(templates.FavoriteTemplateId))
@ -416,6 +424,16 @@ public class MemberIconsDto
/// </summary>
public class NotificationTemplatesDto
{
/// <summary>
/// 服务号验证Token微信公众平台配置的Token
/// </summary>
public string? Token { get; set; }
/// <summary>
/// 服务号消息加解密密钥EncodingAESKey
/// </summary>
public string? EncodingAESKey { get; set; }
/// <summary>
/// 解锁通知模板ID
/// </summary>