admin/src/Oms.Application/Shared/OmsSessionHelper.cs
zzh f4ddd993b9 feat: 管理端列表返回客户名称/编码,并加固绑定与客户会话
订单/包裹/库存/店铺授权/店铺订单列表补充 customerName、customerCode;库存绑定按会话客户解析并兼容可用量;修复客户 mapId 识别与 ConcurrencyStamp 迁移。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-18 11:10:53 +08:00

153 lines
4.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Security.Claims;
using Fake.Application;
using Fake.Users;
using Oms.Domain.CustomersAggregate.Entities;
using Oms.Domain.CustomersAggregate.Repositories;
namespace Oms.Application.Shared;
/// <summary>
/// 从 JWT Claims 解析当前会话类型(管理员 / 客户)。
/// </summary>
public static class OmsSessionHelper
{
/// <summary>
/// JWT 中标识登录类型的 Claim 名称。
/// </summary>
public const string LoginTypeClaim = "loginType";
/// <summary>
/// JWT 中 RBAC mapId Claim 名称(与 FakeClaimTypes.UserId 对齐)。
/// </summary>
public const string MapIdClaim = "mapId";
private const string CustomerLoginType = "1";
private const string CustomerRoleName = "Customer";
/// <summary>
/// 当前会话是否为客户门户登录。
/// </summary>
public static bool IsCustomerLogin(ICurrentUser currentUser)
{
if (string.Equals(
currentUser.FindClaimOrNull(LoginTypeClaim)?.Value,
CustomerLoginType,
StringComparison.Ordinal))
{
return true;
}
// 兼容 loginType 丢失但 role=Customer 仍在的令牌
var role = currentUser.FindClaimOrNull(ClaimTypes.Role)?.Value
?? currentUser.FindClaimOrNull("role")?.Value;
return string.Equals(role, CustomerRoleName, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// 客户登录时返回 mapId(对应 t_customer.UserId / 订单 CreateUserId);管理员返回 null。
/// </summary>
public static int? TryGetCustomerMapId(ICurrentUser currentUser)
{
if (!IsCustomerLogin(currentUser))
{
return null;
}
var userId = currentUser.GetId<int>();
if (userId > 0)
{
return userId;
}
// GetId 未绑到 mapId 时,直接读 claim,避免客户会话被当成管理员(不过滤)
var mapIdRaw = currentUser.FindClaimOrNull(MapIdClaim)?.Value;
if (int.TryParse(mapIdRaw, out var mapId) && mapId > 0)
{
return mapId;
}
return null;
}
/// <summary>
/// 客户登录时返回 mapId(对应订单 CreateUserId);管理员返回 null(不过滤)。
/// </summary>
public static int? TryGetCustomerCreateUserId(ICurrentUser currentUser) =>
TryGetCustomerMapId(currentUser);
/// <summary>
/// 解析当前会话对应的 t_customer 记录(客户按 UserId=mapId;管理员可按 CustomerId 代提交)。
/// </summary>
public static async Task<Customer> ResolveSessionCustomerAsync(
ICustomerRepository customerRepository,
ICurrentUser currentUser,
int? requestedCustomerId = null)
{
var mapId = TryGetCustomerMapId(currentUser);
if (mapId.HasValue)
{
var sessionCustomer = await customerRepository.FirstOrDefaultAsync(x => x.UserId == mapId.Value);
if (sessionCustomer == null)
{
throw new BusinessException("未找到客户信息");
}
if (requestedCustomerId is > 0 && requestedCustomerId.Value != sessionCustomer.Id)
{
throw new BusinessException("客户ID非法");
}
return sessionCustomer;
}
var customerId = requestedCustomerId ?? currentUser.GetId<int>();
if (customerId <= 0)
{
throw new BusinessException("客户ID不能为空");
}
var customer = await customerRepository.FirstOrDefaultAsync(x => x.Id == customerId);
if (customer == null)
{
throw new BusinessException("客户不存在");
}
return customer;
}
/// <summary>
/// 客户登录时强制返回 t_customer.Id;管理员返回入参 customerId。
/// </summary>
public static async Task<int?> ResolveListCustomerIdAsync(
ICustomerRepository customerRepository,
ICurrentUser currentUser,
int? requestedCustomerId)
{
var mapId = TryGetCustomerMapId(currentUser);
if (!mapId.HasValue)
{
return requestedCustomerId;
}
var customer = await customerRepository.FirstOrDefaultAsync(x => x.UserId == mapId.Value);
if (customer == null)
{
throw new BusinessException("未找到客户信息");
}
return customer.Id;
}
/// <summary>
/// 小红书模块客户上下文:客户登录返回 t_customer.Id;管理员无客户上下文时返回 0(系统级)。
/// </summary>
public static async Task<int> ResolveXhsCustomerIdAsync(
ICustomerRepository customerRepository,
ICurrentUser currentUser,
int? requestedCustomerId = null)
{
var customerId = await ResolveListCustomerIdAsync(customerRepository, currentUser, requestedCustomerId);
return customerId ?? 0;
}
}