c# - IHttpContextAccessor.HttpContext.User.Identity 显示 CurrentUserService 服务中的所有空属性

标签 c# dependency-injection identity httpcontext clean-architecture

我正在尝试使用 Jason Taylor's Clean Architecture Template ,这个模板使用NSwag自动创建了一个TypeScript Client(Angular),但是我不需要创建TS客户端,所以我的主要目标是用Razor Pages替换它。我已经能够做到这一点,但当 CurrentUserService 被实例化时,我遇到了问题,它应该在这一行中设置 UserId:

UserId = httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);

这是完整的 CurrentUserService:
using CleanREC0.Application.Common.Interfaces;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;

namespace CleanREC0.WebUI.Services
{
    public class CurrentUserService : ICurrentUserService
    {
        public CurrentUserService(IHttpContextAccessor httpContextAccessor)
        {
            UserId = httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
        }

        public string UserId { get; }
    }
}

第一次甚至 HttpContext 为空,这很好,因为一切都在初始化,但随后的调用总是在所有 httpContextAccessor.HttpContext.User.Identity 属性上返回 null,用户显示了一个身份,但它的所有属性和声明都是null 或 Yield no results,即使用户正确登录。

这是我对模板所做的事情的列表:
  • 摆脱了 NSwag 和所有 TypeScript 相关内容
  • 摆脱了 IdentityServer
  • 为 IdentityDbContext 替换了 ApiAuthorizationDbContext

  • 这是我的 StartUp 类(class):
    public class Startup
        {
            public Startup(IConfiguration configuration, IWebHostEnvironment environment)
            {
                Configuration = configuration;
                Environment = environment;
            }
    
            public IConfiguration Configuration { get; }
            public IWebHostEnvironment Environment { get; }
    
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddApplication();
                services.AddInfrastructure(Configuration, Environment);    
    
                services.AddScoped<ICurrentUserService, CurrentUserService>();
    
                services.AddHttpContextAccessor();
                services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>(); //I have added this line on as suggested on other post, but made no difference.
    
    
                services.AddHealthChecks()
                    .AddDbContextCheck<ApplicationDbContext>();
    
                services.AddRazorPages()
                    .AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<IApplicationDbContext>());
            }
    
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                    app.UseDatabaseErrorPage();
                }
                else
                {
                    app.UseExceptionHandler("/Error");
                    app.UseHsts();
                }
    
                app.UseCustomExceptionHandler();
                app.UseHealthChecks("/health");
                app.UseHttpsRedirection();
                app.UseStaticFiles();
    
                app.UseRouting();
    
                app.UseAuthentication();
                app.UseAuthorization();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapRazorPages();
                });
            }
        }
    

    这是从 ConfigureServices 调用的 AddApplication:
    public static IServiceCollection AddApplication(this IServiceCollection services)
            {
                services.AddAutoMapper(Assembly.GetExecutingAssembly());
                services.AddMediatR(Assembly.GetExecutingAssembly());
                services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPerformanceBehaviour<,>));
                services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestValidationBehavior<,>));
    
                return services;
            }
    

    以及也在那里被调用的 AddInfrastructure:
    public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration, IWebHostEnvironment environment)
            {
                services.AddDbContext<ApplicationDbContext>(options =>
                    options.UseSqlServer(
                        configuration.GetConnectionString("DefaultConnection"), 
                        b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)));
    
                services.AddScoped<IApplicationDbContext>(provider => provider.GetService<ApplicationDbContext>());
    
                services.AddDefaultIdentity<ApplicationUser>()
                    .AddEntityFrameworkStores<ApplicationDbContext>();
    
                if (environment.IsEnvironment("Test"))
                {
    
                }
                else
                {
                    services.AddTransient<IDateTime, DateTimeService>();
                    services.AddTransient<IIdentityService, IdentityService>();
                    services.AddTransient<ICsvFileBuilder, CsvFileBuilder>();
                }
    
                services.AddAuthentication();
    
                return services;
            }
    

    其他一切似乎都运行良好。在 Razor 页面级别,用户变量及其身份包含所有预期信息和声明。

    我确定我遗漏了一些东西,有人可以指出我正确的方向吗?

    最佳答案

    LinkedListT 在评论中的链接让我找到了正确的方向。

    该链接指向一个解释这一点的答案:

    under the ASP.NET MVC framework, the HttpContext (and therefore HttpContext.Session) is not set when the controller class is contructed as you might expect, but it set ("injected") later by the ControllerBuilder class.



    我正在使用的模板附带的 CurrentUserService 类尝试读取构造函数中的用户声明,因此我将代码移动到属性的 getter,它会在实际使用该属性时执行,然后所有声明和属性都是人口稠密。

    我的新 CurrentUserService 如下所示:
    using CleanREC0.Application.Common.Interfaces;
    using Microsoft.AspNetCore.Http;
    using System.Security.Claims;
    
    namespace CleanREC0.WebUI.Services
    {
        public class CurrentUserService : ICurrentUserService
        {
            private IHttpContextAccessor _httpContextAccessor;
    
            public CurrentUserService(IHttpContextAccessor httpContextAccessor)
            {
                _httpContextAccessor = httpContextAccessor;
            }
    
            public string UserId { get { return _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier); }}
        }
    }
    

    关于c# - IHttpContextAccessor.HttpContext.User.Identity 显示 CurrentUserService 服务中的所有空属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59793111/

    相关文章:

    .net - 具有 WCF 调用的单元测试服务 (MSUnit + Moq)

    c# - Asp.Net MVC 5 测试 IoC + 依赖注入(inject)

    language-agnostic - 手动分配实体的 ID 是个好主意吗?

    c# - InvalidProgramException 尝试通过 Reflection.Emit 调用静态方法

    c# Linq 方法不遵循我设置的条件之一

    C# EventHandler - 没有重载与委托(delegate)匹配(嗯?)

    php - 如何在不牺牲依赖注入(inject)的情况下简化 API?

    azure - 更改 AAD B2C 中的登录名

    c# - 使用没有身份的 [Authorize] 属性?

    c# - 在 .net 4 上使用异步等待