C# 当在控制器外部使用时,IHttpContextAccessor包含空的User.Identity
我正在写一个应用程序ASP.NETCore(2.2)MVC。我需要根据登录用户的某些声明的值过滤DbContext中的一些数据。我注入了IHttpContextAccessor,但当我尝试访问HttpContext.User.Identity时,所有属性都为null,所有声明都为空 这就是我努力实现这一目标的方式 我连接了IHttpContextAccessor。我使用这样的标准方法:C# 当在控制器外部使用时,IHttpContextAccessor包含空的User.Identity,c#,asp.net-core,.net-core,asp.net-core-mvc,C#,Asp.net Core,.net Core,Asp.net Core Mvc,我正在写一个应用程序ASP.NETCore(2.2)MVC。我需要根据登录用户的某些声明的值过滤DbContext中的一些数据。我注入了IHttpContextAccessor,但当我尝试访问HttpContext.User.Identity时,所有属性都为null,所有声明都为空 这就是我努力实现这一目标的方式 我连接了IHttpContextAccessor。我使用这样的标准方法: public void ConfigureServices(IServiceCollection servic
public void ConfigureServices(IServiceCollection services){
services.AddHttpContextAccessor();
...
}
然后,我构建一个自定义提供程序,以从用户提取声明:
public class GetClaimsFromUser : IGetClaimsProvider
{
public string UserId {get; private set;}
public GetClaimsFromUser(IHttpContextAccessor accessor)
{
UserId = accessor.HttpContext?.User.Claims.SingleOrDefault(x => x.Type == ClaimTypes.Name)?.Value;
}
}
然后我还将其注入ConfigureServices方法中:
public void ConfigureServices(IServiceCollection services){
...
services.AddScoped<IGetClaimsProvider, GetClaimsFromUser>();
...
}
public void配置服务(IServiceCollection服务){
...
services.addScope();
...
}
之后,我将其注入到ApplicationDbContext中,并尝试在构造函数中设置private _userId字段:
public class ExpenseManagerDbContext: IdentityDbContext<ApplicationUser>
{
private string _userId;
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, IGetClaimsProvider claimsProvider) : base(options)
{
_userId = claimsProvider.UserId;
...
}
...
}
公共类ExpenseManagerDbContext:IdentityDbContext?您正试图访问应用程序的ExpenseManagerDbContext
中的用户。因此,它本身是身份验证系统的依赖项,在框架执行身份验证时将得到解决
所以流程有点像这样:
请求进来了
身份验证中间件运行以对用户进行身份验证
UserManager
解析ExpenseManagerDbContext
ExpenseManagerDbContext
解析IGetClaimsProvider
GetClaimsProvider
解析HttpContext并尝试访问用户的声明
身份验证中间件执行身份验证并使用结果设置HttpContext.User
如果查看步骤5和6,您将看到在身份验证中间件能够实际验证用户并更新上下文上的用户对象之前,HttpContext已经被访问。由于身份验证中间件总是在请求开始时运行,因此情况总是如此
我建议您重新考虑您的ExpenseManagerDbContext
,因为它可能不应该依赖于当前登录的用户。它应该独立于此。如果您的逻辑取决于用户id,那么它可能是一个单独的服务。您正试图在ExpenseManagerDbContext
中访问用户,它是应用程序的IdentityDbContext
。因此,它本身是身份验证系统的依赖项,在框架执行身份验证时将得到解决
所以流程有点像这样:
UserManager
解析ExpenseManagerDbContext
ExpenseManagerDbContext
解析IGetClaimsProvider
GetClaimsProvider
解析HttpContext并尝试访问用户的声明HttpContext.User
ExpenseManagerDbContext
,因为它可能不应该依赖于当前登录的用户。它应该独立于此。如果您的逻辑取决于用户id,那么它可能是一个单独的服务。解决了!
问题在于为IdentityDbContext和ApplicationDataDbContext共享相同的DbContext。
在我的控制器中,我有以下代码:
[Authorize]
public class AccountController : Controller
{
[HttpGet]
public IActionResult Index()
{
var accounts = _accountService.GetAll();
var models = _mapper.Map<List<AccountDto>>(accounts);
return View(models);
}
}
[授权]
公共类AccountController:控制器
{
[HttpGet]
公共IActionResult索引()
{
var accounts=_accountService.GetAll();
var模型=_mapper.Map(账户);
返回视图(模型);
}
}
当我试图从浏览器调用控制器时,由于[Authorize]属性,应用程序第一次初始化了DbContext。这是在没有任何HttpContext的情况下完成的。因此,当应用程序在“_accountService.GetAll()”中调用DbContext时,DbContext已经实例化,并且没有调用构造函数方法,因此,我的所有私有字段都保持为空!
因此,我创建了第二个DbContext类,仅用于身份验证/授权目的
public class ApplicationDbAuthContext : IdentityDbContext
{
public ApplicationDbAuthContext(DbContextOptions<ApplicationDbAuthContext> options) : base(options)
{
}
}
公共类ApplicationBauthContext:IdentityDbContext
{
公共应用程序BauthContext(DbContextOptions选项):基本(选项)
{
}
}
因此,在控制器内的请求期间,当我进行调用时,正确的DbContext被实例化,它包含HttpContext
我将更新回购协议中的代码以显示更改。
同时,感谢所有的答案。解决了!
问题在于为IdentityDbContext和ApplicationDataDbContext共享相同的DbContext。
在我的控制器中,我有以下代码:
[Authorize]
public class AccountController : Controller
{
[HttpGet]
public IActionResult Index()
{
var accounts = _accountService.GetAll();
var models = _mapper.Map<List<AccountDto>>(accounts);
return View(models);
}
}
[授权]
公共类AccountController:控制器
{
[HttpGet]
公共IActionResult索引()
{
var accounts=_accountService.GetAll();
var模型=_mapper.Map(账户);
返回视图(模型);
}
}
当我试图从浏览器调用控制器时,由于[Authorize]属性,应用程序第一次初始化了DbContext。这是在没有任何HttpContext的情况下完成的。因此,当应用程序在“_accountService.GetAll()”中调用DbContext时,DbContext已经实例化,并且没有调用构造函数方法,因此,我的所有私有字段都保持为空!
因此,我创建了第二个DbContext类,仅用于身份验证/授权目的
public class ApplicationDbAuthContext : IdentityDbContext
{
public ApplicationDbAuthContext(DbContextOptions<ApplicationDbAuthContext> options) : base(options)
{
}
}
公共类ApplicationBauthContext:IdentityDb