.NET 5 i Identity - UserManager.GetUserAsync(User) zawsze zwraca null

0

Cześć,

próbuję pobrać aktualnie zalogowanego usera, ale za każdym razem dostaję nulla. Przekopałem internet, wszystkim to rozwiązanie działa poprawnie, a mi nie. Prośba o radę, bo już nie wiem co robię nie tak.

Kontroler (wstrzyknięcie zalezności):

public WeatherForecastController(ILogger<WeatherForecastController> logger, ApplicationDbContext dbx,
            UserManager<ApplicationUser> userService)
        {
            _logger = logger;
            this.dbx = dbx;
            this.userManager = userService;
        }

Kontroler (wywołanie):


var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); //zwraca poprawnie ID

ApplicationUser user = await userManager.GetUserAsync(HttpContext.User); //zwraca null

Startup:

        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }


        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection")));

            services.AddDatabaseDeveloperPageExceptionFilter();

            services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
                .AddRoles<IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>();

            services.AddIdentityServer()
                .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

            services.AddAuthentication()
                .AddIdentityServerJwt();
            services.AddControllersWithViews();
            services.AddRazorPages();

            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/dist";
            });

        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseMigrationsEndPoint();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            if (!env.IsDevelopment())
            {
                app.UseSpaStaticFiles();
            }

            app.UseRouting();

            app.UseAuthentication();
            app.UseIdentityServer();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller}/{action=Index}/{id?}");
                endpoints.MapRazorPages();
            });

            app.UseSpa(spa =>
            {
                spa.Options.SourcePath = "ClientApp";

                if (env.IsDevelopment())
                {
                    spa.UseAngularCliServer(npmScript: "start");
                }
            });
        }
2

Ja bym zaczął od tego czy:

  • UseAuthentication w Startup.cs jest w odpowiednim miejscu rurociągu,
  • zdebugował, czy HttpContext.User nie jest null (może być automatycznie wylogowany z jakiegoś powodu),
  • zdebugował czy HttpContext.User, jest jest w ogóle w bazie.

Też nie znam AddDefaultIdentity i AddIdentityServerJwt, nie wiem czy są wykorzystane prawidłowo.

0

@bakunet: Dzieki za odpowiedź. Co do Startupu - jest to defaultowy projekt z VS 2019 (Nowy projekt .Net 5 + Angular i dodatkowo zaznaczone to co na screenie).

screenshot-20210802200143.png

Dlatego dziwi mnie to, ze to nie dziala bo to out of the box od MS.

Co do HttpContext.User:
Debug:
screenshot-20210802201218.png

Baza:
screenshot-20210802201324.png

Jakieś pomysły gdzie jeszcze mogę szukać?

2

Ja zawsze używałem takiego konstruktora

        public LoginController(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager)
        {
            _userManger = userManager;
            _signInManager = signInManager;
        }

Nie wiem czy twój jest także poprawny ale może spróbuj zmienić
Tylko pamiętaj ,że wtedy user pochodzi z ClaimsPrincipal

0

@Botek: Nadal to samo.

ApplicationUser dziedziczy po IdentityUser wiec to nie mogło zadziałać.

1

@kobi55:

Ciekawe. A znając i mając już ID usera spróbuj, co Ci zwróci:
var user = await userManager.FindByIdAsync(model.userId);

0

@bakunet: Ten sposób (oraz pobranie danych bezposrednio z DB działają):

screenshot-20210802210745.png

0

Próbowałeś zamiast HttpContext.User użyć po prostu User, który pochodzi z klasy ControllerBase?

0

@Botek: Tak, próbowałem i tego i tego.

0

Kończą mi się powoli pomysł może pokaż jak wygląda rejestracja tego użytkownika.

0

@Botek: Ten user to admin i jest rejestrowany przy uruchomieniu aplikacji (sprawdzanie czy istenieje, jezeli nie to dodanie):

            var poweruser = new ApplicationUser
            {
                UserName = "[email protected]",
                Email = "[email protected]",
                EmailConfirmed = true
            };

            string userPWD = "***";

            var user = await userManager.FindByEmailAsync(poweruser.Email);

            if (user == null)
            {
                var createPowerUser = await userManager.CreateAsync(poweruser, userPWD);

                if (createPowerUser.Succeeded)
                    await userManager.AddToRoleAsync(poweruser, "Admin");
            }
0

Czy HttpContext.User zwraca zalogowanego użytkownika? Obstawiam że nie. Gdzie w ogóle logujesz użytkownika? Co się stanie jeśli najpierw zaladujesz użytkownika z bazy, i wywolasz signInManager.SignInAsync?

Ewentualnie sprawdź co zwraca userManager.GerUserId. Czy to ID użytkownika którego chcesz znaleźć?

1

Ja tylko przykleję treść dokumentacji.

// Summary:
// Returns the user corresponding to the IdentityOptions.ClaimsIdentity.UserIdClaimType
// claim in the principal or null.
//
// Parameters:
// principal:
// The principal which contains the user id claim.
//
// Returns:
// The user corresponding to the IdentityOptions.ClaimsIdentity.UserIdClaimType
// claim in the principal or null
public virtual Task<TUser> GetUserAsync(ClaimsPrincipal principal);

A Ty w innym miejscu trzymasz id.

1 użytkowników online, w tym zalogowanych: 0, gości: 1