【问题标题】:Injected IPrincipal Claims empty after adding Claims Transformer添加 Claims Transformer 后注入的 IPrincipal Claims 为空
【发布时间】:2019-10-10 07:51:01
【问题描述】:

我正在尝试使用 ASP.NET Core 中的 Windows 身份验证来使用基于声明的授权。我有一个设置用户声明的声明转换器。我还将IPrincipal 注入到DbContext 中,这样我就可以在调用SaveChanges() 以记录谁更新了实体时访问当前用户。

在 Startup.cs 中:

    services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>()?.HttpContext?.User);
    services.AddTransient<IClaimsTransformation, MyClaimsTransformer>();

在 MyDbContext.cs 中:

    protected readonly IPrincipal _principal ;

    public MyDbContext(DbContextOptions<MyDbContext> options, IPrincipal principal) : base(options)
    {
        _principal = principal;
    }

    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
    {
        // Do something with Claim value...
        await base.SaveChangesAsync(cancellationToken);
    }

我添加了一个声明转换器来添加一些声明信息:

    public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        // Add Claims...
        return principal;
    }

SaveChangesAsync 在用户中间件中被调用以记录对应用程序的访问。在添加 Claims Transformer 之前,注入到 DbContext 中的 IPrincipalWindowsPrincipal,它包含我需要的 Claims,例如 PrimarySid 等。现在添加转换后,它是 ClaimsPrincipal 但是列表of Claims 现在为空。

通过调试,我可以验证 TransformAsyncSaveChangesAsync 之前执行,但是 db 上下文中的构造函数注入发生在转换之前(DbContext 是 Scoped 服务,Claims Transfomer 是瞬态的)。

总结:

  • 在添加声明转换器之前,注入的IPrincipal 是一个包含声明列表的WindowsPrincipal
  • 添加 Claims Transformer 后,注入的 IPrincipal 是一个带有空声明列表的 ClaimsPrincipal

【问题讨论】:

  • 将其添加为范围服务
  • @Nkosi 我已经尝试将其他服务更改为 Scoped,没有区别。

标签: c# asp.net-core dependency-injection


【解决方案1】:

尝试通过 DbContext 构造函数注入 IPrincipal 时,我遇到了完全相同的问题。我发现注入到 DbContext 中的 IPrincipal 尚未被 ClaimsTransformer“转换”。

我通过创建 UserResolverService 解决了这个问题。

IUserResolverService.cs

public interface IUserResolverService
{
    IPrincipal GetUser();
}

UserResolverService.cs

public class UserResolverService : IUserResolverService
{
    private readonly IHttpContextAccessor _context;

    public UserResolverService(IHttpContextAccessor context)
    {
        _context = context;
    }

    public IPrincipal GetUser()
    {
        return _context.HttpContext.User;
    }
}

MyDbContext.cs

private readonly IUserResolverService _userResolverService;

// Call this whenever you need the IPrincipal object
public IPrincipal User => _userResolverService.GetUser();

public MyDbContext(IUserResolverService userResolverService, DbContextOptions<MyDbContext> options)
        : base(options)
{
    _userResolverService = userResolverService;
}

Startup.cs

services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
services.AddTransient<IUserResolverService, UserResolverService>();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-30
    • 2020-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多