我试图在ASP.NET Core中使用Windows身份验证使用基于声明的授权。我有一个Claims变压器,可以设置用户的Claims。我还将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);
}
我添加了Claims变形器以添加一些Claim信息:
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
// Add Claims...
return principal;
}
在用户中间件中调用 SaveChangesAsync
来记录对应用程序的访问。在添加Claims Transformer之前,注入IPrincipal
的{{1}}是DbContext
,它包含我需要的Claims,例如PrimarySid等。现在添加转换之后,它是一个WindowsPrincipal
,但“索赔”列表现在为空。
通过调试,我可以验证ClaimsPrincipal
在TransformAsync
之前执行,但是db上下文中的构造函数注入发生在转换之前(SaveChangesAsync
是作用域服务,Claims Transfomer是瞬态)。
摘要:
DbContext
是带有声明的列表的IPrincipal
。WindowsPrincipal
是IPrincipal
,其中的Claims列表为空。答案 0 :(得分:0)
当尝试通过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>();