feat: add tencent map signature endpoint

This commit is contained in:
2026-01-21 12:35:39 +08:00
parent 36abd83e83
commit 60f12b3e58
4 changed files with 101 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
namespace TakeoutSaaS.AdminApi.Contracts.Responses;
public sealed record TencentMapScriptResponse(string ScriptUrl);

View File

@@ -0,0 +1,90 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Cryptography;
using System.Text;
using TakeoutSaaS.AdminApi.Contracts.Responses;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Results;
using TakeoutSaaS.Shared.Web.Api;
namespace TakeoutSaaS.AdminApi.Controllers;
/// <summary>
/// 腾讯地图脚本签名服务。
/// </summary>
[ApiVersion("1.0")]
[Authorize]
[Route("api/admin/v{version:apiVersion}/maps")]
public sealed class TencentMapsController(IConfiguration configuration) : BaseApiController
{
private const string DefaultLibraries = "visualization,geometry,vector,tools";
private const string DefaultCallback = "initGLMap";
private const string DefaultVersion = "1.exp";
/// <summary>
/// 获取腾讯地图 JS 脚本地址(含签名)。
/// </summary>
[HttpGet("tencent-js")]
[ProducesResponseType(typeof(ApiResponse<TencentMapScriptResponse>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status400BadRequest)]
public ApiResponse<TencentMapScriptResponse> GetTencentJsScript(
[FromQuery] string? libraries,
[FromQuery] string? callback,
[FromQuery] string? v)
{
// 1. 读取配置
var key = configuration.GetValue<string>("TencentMap:Key");
var sk = configuration.GetValue<string>("TencentMap:Sk");
if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(sk))
{
return ApiResponse<TencentMapScriptResponse>.Error(ErrorCodes.BadRequest, "未配置腾讯地图 Key/SK");
}
// 2. 规范化参数
var resolvedLibraries = string.IsNullOrWhiteSpace(libraries) ? DefaultLibraries : libraries;
var resolvedCallback = string.IsNullOrWhiteSpace(callback) ? DefaultCallback : callback;
var resolvedVersion = string.IsNullOrWhiteSpace(v) ? DefaultVersion : v;
// 3. 构建签名
var parameters = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
["callback"] = resolvedCallback,
["key"] = key,
["libraries"] = resolvedLibraries,
["v"] = resolvedVersion
};
var queryString = BuildQueryString(parameters);
var signature = ComputeSignature("/api/gljs", queryString, sk);
var scriptUrl = $"https://map.qq.com/api/gljs?{queryString}&sig={signature}";
return ApiResponse<TencentMapScriptResponse>.Ok(new TencentMapScriptResponse(scriptUrl));
}
private static string BuildQueryString(IEnumerable<KeyValuePair<string, string>> parameters)
{
var builder = new StringBuilder();
foreach (var (key, value) in parameters)
{
if (builder.Length > 0)
{
builder.Append('&');
}
builder.Append(key);
builder.Append('=');
builder.Append(Uri.EscapeDataString(value));
}
return builder.ToString();
}
private static string ComputeSignature(string path, string queryString, string sk)
{
var raw = $"{path}?{queryString}{sk}";
var hash = MD5.HashData(Encoding.UTF8.GetBytes(raw));
var builder = new StringBuilder(hash.Length * 2);
foreach (var b in hash)
{
builder.Append(b.ToString("x2"));
}
return builder.ToString();
}
}

View File

@@ -139,6 +139,10 @@
"AntiLeechTokenSecret": "ReplaceWithARandomToken"
}
},
"TencentMap": {
"Key": "DGIBZ-YUM64-5ONUT-F4RIA-MPUP2-XFFXZ",
"Sk": "6ztzMqwtuOyaJLuBs1koRDyqNpnVyda8"
},
"Sms": {
"Provider": "Tencent",
"DefaultSignName": "外卖SaaS",

View File

@@ -139,6 +139,10 @@
"AntiLeechTokenSecret": "ReplaceWithARandomToken"
}
},
"TencentMap": {
"Key": "DGIBZ-YUM64-5ONUT-F4RIA-MPUP2-XFFXZ",
"Sk": "6ztzMqwtuOyaJLuBs1koRDyqNpnVyda8"
},
"Sms": {
"Provider": "Tencent",
"DefaultSignName": "外卖SaaS",