fix(track): forward Authorization Bearer to UpsertSmallBag

Track gateway requires the logged-in user JWT in addition to appKey/timestamp/sign headers. Capture token before async enqueue so background sync still works.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zzh 2026-06-29 12:53:28 +08:00
parent bd1288edc9
commit 3046f26837
4 changed files with 67 additions and 4 deletions

View File

@ -1,8 +1,9 @@
# 单独调试 POST /OrderV2/UpsertSmallBag(与 SmallBagTrackOrderClient 一致:鉴权走 Header)
# 单独调试 POST /OrderV2/UpsertSmallBag(与 SmallBagTrackOrderClient 一致:鉴权走 Header + Bearer)
param(
[string]$BaseUrl = "https://api.nanafa.com/track",
[string]$AppKey = "W2606001",
[string]$AppSecret = "ziK8UzlQ39m3kdL346XEBg8nljY8os52",
[string]$Authorization = "",
[string]$OrderNo = "",
[string]$Client = "TEST001"
)
@ -45,13 +46,25 @@ $url = ($BaseUrl.TrimEnd('/')) + "/OrderV2/UpsertSmallBag"
Write-Host "========== UpsertSmallBag Debug ==========" -ForegroundColor Cyan
Write-Host "URL: $url"
Write-Host "Headers: appKey=$AppKey, timestamp=$timestamp, sign=$sign"
if (-not [string]::IsNullOrWhiteSpace($Authorization)) {
Write-Host "Headers: Authorization=<provided>"
}
Write-Host "Body:"
Write-Host ($body | ConvertFrom-Json | ConvertTo-Json -Depth 5)
Write-Host "========================================" -ForegroundColor Cyan
try {
$headers = @{
appKey = $AppKey
timestamp = "$timestamp"
sign = $sign
}
if (-not [string]::IsNullOrWhiteSpace($Authorization)) {
$headers.Authorization = $Authorization
}
$response = Invoke-WebRequest -Uri $url -Method POST `
-Headers @{ appKey = $AppKey; timestamp = "$timestamp"; sign = $sign } `
-Headers $headers `
-ContentType "application/json; charset=utf-8" `
-Body ([System.Text.Encoding]::UTF8.GetBytes($body)) `
-UseBasicParsing
@ -69,6 +82,6 @@ catch {
Write-Host $_.Exception.Message -ForegroundColor Red
}
Write-Host ""
Write-Host "Tip: track SignatureValidationFilter reads appKey/timestamp/sign from HTTP Headers." -ForegroundColor Yellow
Write-Host "Tip: track gateway requires Authorization Bearer from logged-in user, plus appKey/timestamp/sign headers." -ForegroundColor Yellow
exit 1
}

View File

@ -1,5 +1,7 @@
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace Oms.Application.Integrations.SmallBagTrack;
@ -7,6 +9,7 @@ namespace Oms.Application.Integrations.SmallBagTrack;
internal sealed class SmallBagTrackOrderClient(
IHttpClientFactory httpClientFactory,
ISmallBagTrackConfigProvider configProvider,
IHttpContextAccessor httpContextAccessor,
ILogger<SmallBagTrackOrderClient> logger) : ISmallBagTrackOrderClient
{
private static readonly JsonSerializerOptions JsonOptions = new()
@ -68,10 +71,18 @@ internal sealed class SmallBagTrackOrderClient(
var sign = SmallBagTrackSignHelper.GenerateSign(appKey, timestamp, settings.AppSecret.Trim());
var body = SmallBagTrackUpsertApiRequest.FromBusinessRequest(request);
var url = SmallBagTrackUpsertApiRequest.BuildEndpointUrl(settings.BaseUrl);
var authorization = ResolveAuthorization(request);
var requestJson = JsonSerializer.Serialize(
new
{
auth = new { appKey, timestamp, sign, transport = "header" },
auth = new
{
appKey,
timestamp,
sign,
transport = "header",
authorizationForwarded = !string.IsNullOrWhiteSpace(authorization)
},
body
},
JsonOptions);
@ -80,6 +91,7 @@ internal sealed class SmallBagTrackOrderClient(
httpRequest.Headers.TryAddWithoutValidation("appKey", appKey);
httpRequest.Headers.TryAddWithoutValidation("timestamp", timestamp.ToString());
httpRequest.Headers.TryAddWithoutValidation("sign", sign);
ApplyAuthorization(httpRequest, authorization);
httpRequest.Content = JsonContent.Create(body, options: JsonOptions);
var client = httpClientFactory.CreateClient(HttpClientName);
@ -98,6 +110,26 @@ internal sealed class SmallBagTrackOrderClient(
};
}
private string? ResolveAuthorization(SmallBagTrackUpsertRequest request)
{
if (!string.IsNullOrWhiteSpace(request.Authorization))
{
return request.Authorization.Trim();
}
return httpContextAccessor.HttpContext?.Request.Headers.Authorization.ToString();
}
private static void ApplyAuthorization(HttpRequestMessage httpRequest, string? authorization)
{
if (string.IsNullOrWhiteSpace(authorization))
{
return;
}
httpRequest.Headers.Authorization = AuthenticationHeaderValue.Parse(authorization);
}
private static SmallBagTrackUpsertResult Skipped(string reason) =>
new()
{

View File

@ -20,6 +20,11 @@ public class SmallBagTrackUpsertRequest
public string ApiCode { get; set; } = string.Empty;
public SmallBagTrackConsigneeRequest Consignee { get; set; } = new();
/// <summary>
/// 转发到轨迹网关的 Authorization(异步入队前从当前 HTTP 请求捕获)。
/// </summary>
public string? Authorization { get; set; }
}
public class SmallBagTrackConsigneeRequest

View File

@ -1,4 +1,5 @@
using Fake.Application;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Oms.Application.Dtos.Channels;
using Oms.Application.Dtos.Orders;
@ -1444,6 +1445,18 @@ public partial class OrderService
OrderParcelReceiverInput? receiver)
{
var request = await BuildSmallBagTrackUpsertRequestAsync(order, receiver);
var authorization = LazyServiceProvider
.GetRequiredService<IHttpContextAccessor>()
.HttpContext?
.Request
.Headers
.Authorization
.ToString();
if (!string.IsNullOrWhiteSpace(authorization))
{
request.Authorization = authorization;
}
SmallBagTrackOrderNotifier.Enqueue(request);
}