HttpContext.User 身份信息总是返回 null
我使用 .net 核心 3.1.6.关于这个有很多答案,我尝试了所有但每次都失败了.所以我创建了新的测试 MVC 项目并添加了身份验证.
I use .net core 3.1.6. There are lots of answer about this and I try all but failed each time. So I create new test MVC project and add authentication.
我尝试使用CurrentUserService"类并获取登录的用户信息.但是,每次我都得到空结果.
I try to use a "CurrentUserService" class and get logged user information. However, every each time I get null result.
我的startup.cs
My startup.cs
public void ConfigureServices(IServiceCollection services) {
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddHttpContextAccessor();
services.AddScoped<ICurrentUserService, CurrentUserService>();
services.AddControllersWithViews();
services.AddRazorPages();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else {
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
还有我的 CurrentUserService.cs
And my CurrentUserService.cs
public class CurrentUserService : ICurrentUserService {
private IHttpContextAccessor _httpContextAccessor;
public CurrentUserService(IHttpContextAccessor httpContextAccessor) {
_httpContextAccessor = httpContextAccessor;
//I add x for test purpose and there is no user information here.
var x = _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
}
public string UserId {
get {
var userIdClaim = _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
return userIdClaim;
}
}
public bool IsAuthenticated => UserId != null;
}
ICurrentUser.cs
ICurrentUser.cs
public interface ICurrentUserService {
string UserId { get; }
bool IsAuthenticated { get; }
}
DbContext.cs
DbContext.cs
public class ApplicationDbContext : IdentityDbContext {
private readonly ICurrentUserService _currentUserService;
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options) {
}
public ApplicationDbContext(
DbContextOptions<ApplicationDbContext> options,
ICurrentUserService currentUserService)
: base(options) {
_currentUserService = currentUserService;
}
}
调试屏幕截图:
HttpContext
仅在请求期间有效.Startup 中的 Configure
方法不是网络调用,而是,因此,没有 HttpContext
.当 .NET Core 为对 Configure
的调用创建 ApplicationDbContext
类时,没有有效的上下文.
HttpContext
is only valid during a request.The Configure
method in Startup is not a web call and, as such, does not have a HttpContext
. When .NET Core creates an ApplicationDbContext
class for the call to Configure
there is no valid context.
当您发送请求Home/Index
时,您可以在控制器中获取HttpContext
:
You could get the HttpContext
in the controller when you send request Home/Index
:
public class HomeController : Controller
{
private IHttpContextAccessor _httpContextAccessor;
public HomeController(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
var x = _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier); //get in the constructor
}
public IActionResult Index()
{
// you could also get in your method
var x = _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
return View();
}
}
结果:
更新:
只有调用这个服务,才能得到数据:
Only if you call this service,then you could get the data:
public class HomeController : Controller
{
private readonly ICurrentUserService _service;
public HomeController(ICurrentUserService service)
{
_service = service;
}
public IActionResult Index()
{
var data = _service.UserId;
return View();
}
}
如果要获取中间件中的数据,请检查:
If you want to get the data in the middleware,please check:
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.Use(async (context, next) =>
{
await next.Invoke();
var data = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
更新 2:
无论你用哪种方式创建ApplicationDbContext
实例,除非你调用它,否则它无法单独获取服务.无论如何,你总是需要在下一个业务层调用服务.
No matter which way you create the ApplicationDbContext
instance,it could not separately get the service unless you call it.Anyway,you always need to call the service in the next business layer.
简单的方法是创建一个新方法然后调用ApplicationDbContext:
The simple way is to create a new method then you call ApplicationDbContext:
1.ApplicationContext:
1.ApplicationContext:
public class ApplicationDbContext : IdentityDbContext
{
private readonly ICurrentUserService _currentUserService;
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public ApplicationDbContext(
DbContextOptions<ApplicationDbContext> options,
ICurrentUserService currentUserService)
: base(options)
{
_currentUserService = currentUserService;
}
public string GetId()
{
var data = _currentUserService.UserId;
return data;
}
}
2.控制器:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly ApplicationDbContext _context;
public HomeController(ILogger<HomeController> logger, ApplicationDbContext context)
{
_context = context;
_logger = logger;
}
public IActionResult Index()
{
var data = _context.GetId();
return View();
}
}