从静态 ClaimsPrincipal 访问迁移

当前的 ClaimsPrincipal 是经过身份验证的 Web 应用程序的基本组件,提供对当前用户的标识和声明的访问权限。 从 ASP.NET Framework 迁移到 ASP.NET Core 时,访问这会带来独特的挑战,因为两个框架对用户上下文管理有不同的方法。

为什么静态 ClaimsPrincipal 迁移很复杂

ASP.NET Framework 和 ASP.NET Core 采用基本不同的方法来访问当前用户:

这些差异意味着不能简单地在 ASP.NET Core 中使用静态主体属性(ClaimsPrincipal.CurrentThread.CurrentPrincipal)而不进行更改。 默认情况下,不会设置静态属性,并且需要更新代码,以便通过不同的方式获取当前经过身份验证的用户标识。

迁移策略概述

在迁移过程中,有两种处理静态主体访问的主要方法:

  1. 完全重写 - 重写所有静态主体访问代码以使用 ASP.NET Core 的原生模式
  2. System.Web 适配器 - 在增量迁移期间使用适配器启用静态访问模式

对于大多数应用程序,迁移到 ASP.NET Core 原生的 ClaimsPrincipal 访问可提供最佳性能和系统可维护性。 但是,在增量迁移期间,较大的应用程序或具有广泛静态主体用法的应用程序可能受益于使用 System.Web 适配器。

选择迁移方法

有两个主要选项用于将静态主体访问从 ASP.NET Framework 迁移到 ASP.NET Core。 选择取决于迁移时间线、是否需要同时运行这两个应用程序,以及你愿意重写的代码量。

快速决策指南

回答以下问题以选择你的方法:

  1. 是否执行完全重写或增量迁移?

  2. 共享库是否具有广泛的静态主体用法(ClaimsPrincipal.CurrentThread.CurrentPrincipal) ?

迁移方法比较

方法 代码更改 性能 共享库 何时使用
完全重写 高 - 重写所有静态主体访问 最佳 需要更新 完全重写,性能关键型应用
System.Web 适配器 低 - 保留现有模式 使用现有代码 增量迁移,广泛的静态访问

完全重写到 ASP.NET Core 模式

执行完整迁移或希望获得最佳性能和可维护性时,请选择此方法。

ASP.NET Core 提供了多个选项,用于检索当前经过身份验证的用户, ClaimsPrincipal 而无需依赖静态属性。 此方法需要重写静态主体访问代码,但长期提供最大的好处。

完整重写的优缺点

优点 缺点
最佳性能 需要重写所有静态主体访问代码
更具可测试性 (依赖注入) 无自动迁移路径
无静态依赖项 新模式的学习曲线
本机 ASP.NET Core 实现 框架模式的重大更改
设计上即具备线程安全性 跨共享库的潜在重构

ASP.NET Core ClaimsPrincipal 访问模式

有几种选项可以在 ASP.NET Core 中检索当前经过身份验证的用户 ClaimsPrincipal,以替代 ClaimsPrincipal.Current

  • ControllerBase.User
  • HttpContext.User
  • 从调用方传入。 不具有当前 HttpContext 访问权限的库通常从控制器或中间件组件调用,并且可以将当前用户的标识作为参数传递。
  • IHttpContextAccessor。 迁移到 ASP.NET Core 的项目可能太大,无法轻松地将当前用户的标识传递到所有必要位置。 在这种情况下, IHttpContextAccessor 可以用作解决方法。 这并不理想,因为它在幕后使用静态访问器。 如果可能,首选更直接的选项。

代码示例

下面是迁移常见静态主体使用模式的示例:

ASP.NET 框架(之前):

public class UserService
{
    public string GetCurrentUserId()
    {
        // Both ClaimsPrincipal.Current and Thread.CurrentPrincipal work interchangeably
        return ClaimsPrincipal.Current?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        // or: return Thread.CurrentPrincipal?.Identity?.Name;
    }
}

ASP.NET Core (after) - 将 ClaimsPrincipal 作为参数传递:

public class UserService
{
    public string GetCurrentUserId(ClaimsPrincipal user)
    {
        return user?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
    }
}

// Usage in controller
public class HomeController : Controller
{
    private readonly UserService _userService;
    
    public HomeController(UserService userService)
    {
        _userService = userService;
    }
    
    public IActionResult Index()
    {
        var userId = _userService.GetCurrentUserId(User);
        return View();
    }
}

ASP.NET Core(后)- 依赖注入:

public class UserService
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    
    public UserService(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }
    
    public string GetCurrentUserId()
    {
        return _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
    }
}

何时选择此方法

  • 可以重写静态主体访问代码
  • 性能是最高优先级(在这种情况下,更倾向于将标识作为参数传递,而不是 DI)
  • 想要消除静态依赖
  • 你不与旧版应用程序共享代码
  • 你需要最可测试且可维护的解决方案

System.Web 适配器

注释

这利用 System.Web 适配器 来简化迁移。

如果需要在增量迁移期间维护现有的静态主体使用模式,或者具有难以更新的大量共享库,请选择此方法。

System.Web 适配器可以在 ASP.NET Core 中启用 ClaimsPrincipal.CurrentThread.CurrentPrincipal 支持,从而在以增量方式迁移时保留现有代码范式。 配置适配器后,这两个属性可互换工作。

System.Web 适配器优点和缺点

优点 缺点
所需的最少代码更改 性能开销
与现有共享库配合使用 在所有情况下都不是线程安全的
启用增量迁移 需要 System.Web 适配器依赖项
维护熟悉的模式 应该是临时解决方案
适用于大型代码库 可测试性小于 DI 模式

设置静态主体支持

要在使用 System.Web 适配器时启用 ClaimsPrincipal.CurrentThread.CurrentPrincipal 的静态主体支持,终结点必须使用 SetThreadCurrentPrincipalAttribute 元数据进行标注:

// Add to controller or action
[SetThreadCurrentPrincipal]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        // Both ClaimsPrincipal.Current and Thread.CurrentPrincipal are now available
        var user1 = ClaimsPrincipal.Current;
        var user2 = Thread.CurrentPrincipal;
        return View();
    }
}

何时使用 System.Web 适配器

  • 跨共享库使用广泛的静态主体使用情况
  • 您正在进行增量迁移
  • 您无法立即承担重新编写所有静态主体访问代码的成本。
  • 需要保持与现有 ASP.NET Framework 代码的兼容性
  • 你了解性能和线程影响

迁移注意事项

性能影响

  • 本地 ASP.NET Core 模式 提供最佳性能,没有额外的开销
  • System.Web 适配器 引入了一些性能开销,但使逐步迁移成为可能。
  • 应避免静态变量,因为它们可能导致内存泄漏和线程处理问题