IHttpContextAccessor.HttpContext.User.Identity показывает все нулевые свойства в сервисе CurrentUserService - PullRequest
1 голос
/ 17 января 2020

Я пытаюсь использовать Шаблон чистой архитектуры Джейсона Тейлора , этот шаблон использует NSwag для автоматического создания клиента TypeScript (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 имеет значение null , и это нормально, поскольку все инициализируется, но последующие вызовы всегда возвращать null для всех httpContextAccessor.HttpContext.User.Identity свойств, пользователь показывает Identity в порядке, но все его свойства и утверждения null или Не дает результатов , даже если пользователь правильно вошел в систему.

Вот список действий, которые я сделал с шаблоном:

  • Избавился от NSwag и всего TypeScript Связано
  • Избавилось от IdentityServer
  • Заменено ApiAuthorizationDbContext для IdentityDbContext

Это мой класс запуска:

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();
            });
        }
    }

Это AddApplication , который вызывается из ConfigureServices :

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 Page переменная Пользователь и ее Идентичность содержат всю ожидаемую информацию и утверждения.

Я уверен, что что-то упустил Может кто-нибудь, пожалуйста, укажите мне в правильном направлении?

1 Ответ

1 голос
/ 18 января 2020

Ссылка LinkedListT в комментариях подтолкнула меня в правильном направлении.

Ссылка указывает на ответ, который объясняет это:

под ASP. NET MVC Framework, HttpContext (и, следовательно, HttpContext.Session) не устанавливается, когда класс контроллера создается, как вы могли ожидать, но он устанавливается («вводится») позже классом ControllerBuilder.

Класс CurrentUserService , который поставляется с шаблоном, который я использую, пытается прочитать утверждения пользователя в конструкторе, поэтому я переместил код в метод получения свойства, который выполняется до последнего, когда свойство фактически используется, тогда все утверждения и свойства будут заполнены.

Мой новый 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); }}
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...