web-dev-qa-db-ja.com

User.Identity.Nameは常にnullであり、PasswordSignInAsync MVC .Net Core 3.0の後にクレームカウント0

ASP.NET MVC Core 3.0では解決できない問題があります。ログイン後、結果は成功し、サインインしている場合は必要なページに正常に戻ります。Cookieまたはセッションを確認すると、APIがそれらを正常に追加したことがわかります。しかし、User.Identity.Nameを取得しようとすると、常にnullになり、isAuthenticatedは常にfalseになります。それはapp.UseAuthentication()がcookieやセッションを読み取らないようです。

私のstartup.cs

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

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContextPool<AnisubsDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("AnisubsDBConnection")));

        services.AddIdentity<IdentityUser, IdentityRole>()
            .AddEntityFrameworkStores<AnisubsDbContext>()
            .AddDefaultTokenProviders();
        services.AddMvc();
        services.AddControllersWithViews();


        services.AddAuthentication(options =>
        {
            options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        })
            .AddFacebook(facebookOptions =>
            {
                facebookOptions.AppId = "353222242210621";
                facebookOptions.AppSecret = "XXXX";
                facebookOptions.CallbackPath = new Microsoft.AspNetCore.Http.PathString("/Login/Callback");
            })
            .AddGoogle(googleOptions =>
            {
                googleOptions.ClientId = "1093176997632-ug4j2h7m9f1nl9rg8nucecpf9np0isro.apps.googleusercontent.com";
                googleOptions.ClientSecret = "XXXX";
                googleOptions.CallbackPath = new Microsoft.AspNetCore.Http.PathString("/Login/Callback");
            })
            .AddTwitter(twitterOptions =>
            {
                twitterOptions.ConsumerKey = "lZ2ugpLuKpDOlmdSuyw1hVJLU";
                twitterOptions.ConsumerSecret = "XXXX";
                twitterOptions.CallbackPath = new Microsoft.AspNetCore.Http.PathString("/Login/Callback");
            })
            .AddMicrosoftAccount(microsoftOptions =>
            {
                microsoftOptions.ClientId = "22f501ab-70c9-4054-8f33-2b35af3a64ba";
                microsoftOptions.ClientSecret = "XXXX";
                microsoftOptions.CallbackPath = new Microsoft.AspNetCore.Http.PathString("/Login/Callback");
            })
            .AddCookie();
    }

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

        app.UseRouting();
        app.UseAuthentication();
        app.UseAuthorization();
        app.UseHttpsRedirection();

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

LoginController.cs

[HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel loginViewModel)
    {
        if (ModelState.IsValid)
        {
            var user = await userManager.FindByEmailAsync(loginViewModel.Email);
            if (user != null)
            {
                var result = await signInManager.PasswordSignInAsync(user.UserName, loginViewModel.Password, loginViewModel.RememberMe, false);
                if (result.Succeeded)
                {
                    return RedirectToAction("Index", "Home");
                }
            }
            ModelState.AddModelError(string.Empty, "Invalid Login Attempt");
        }
        return View(loginViewModel);
    }

ホームページへのリダイレクト後のセッション enter image description here

Razorページ共有_navbarlayout.cshtml(_layout.cshtml内の部分ビュー)

@using Microsoft.AspNetCore.Identity

@inject SignInManager<IdentityUser> signInManager;


<nav class="navbar fixed-top">


    <a class="navbar-logo" href="Dashboard.Default.html">
        <span class="logo d-none d-xs-block"></span>
        <span class="logo-mobile d-block d-xs-none"></span>
    </a>

    <div class="navbar-right">
        <div class="header-icons d-inline-block align-middle">
        <div class="user d-inline-block">
            <button class="btn btn-empty p-0" type="button" data-toggle="dropdown" aria-haspopup="true"
                    aria-expanded="false">
                @if (signInManager.IsSignedIn(User))
                {
                    <span class="name">@User.Identity.Name</span>
                }
                else
                {
                    <span class="name">Not Registered</span>
                }

                <span>
                    <img alt="Profile Picture" src="img/profile-pic-l.jpg" />
                </span>
            </button>

            <div class="dropdown-menu dropdown-menu-right mt-3">
                @if (signInManager.IsSignedIn(User))
                {
                    <a class="dropdown-item" href="#">Account</a>
                    <a class="dropdown-item" href="#">Features</a>
                    <a class="dropdown-item" href="#">History</a>
                    <a class="dropdown-item" href="#">Support</a>
                    <a class="dropdown-item" asp-action="logout" asp-controller="account">Sign out</a>
                }
                else
                {
                    <a class="dropdown-item" asp-action="login" asp-controller="account">Login</a>
                    <a class="dropdown-item" asp-action="register" asp-controller="account">Register</a>
                }
            </div>
        </div>
    </div>
</nav>

上記のかみそりのコードから、signInManager.IsSignedIn(User)は常にfalse、User.identityクレームは常にゼロをカウントします。

以下のように起動ミドルウェアの順序を変更しましたが、問題は同じです

app.UseStaticFiles();
            app.UseHttpsRedirection();

            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();

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

以下は、クイックウォッチユーザーの場合の外観のGIF画像です enter image description here

5
Afterlife

ASP.NET Core IdentityはCookie(スクリーンショットでは.AspNetCore.Identity.Applicationとして表示)を作成します。これは、PasswordSignInAsyncの呼び出しが成功した後に設定されます。 Startup.ConfigureServicesAddIdentityを呼び出すと、これが設定されます。これにより、Identity.Applicationという名前の認証スキームが登録され、アプリケーションのデフォルトの認証スキームとして設定されます。

これを念頭に置いて、質問から次のコードを取得します。

services.AddAuthentication(options =>
 {
     options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
     options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
     options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
 })

上記で明らかなように、このAddAuthenticationへの呼び出しoverridesデフォルトの認証スキームはCookieAuthenticationDefaults.AuthenticationSchemeになります。これはPasswordSignInAsyncIdentity.Applicationスキームでユーザーを正しくサインインすることになりますが、アプリケーションは現在のユーザーにロードしようとするときにCookiesスキームを使用しています。当然、これはユーザーがロードされないことを意味します。

ソリューションに関しては、AddAuthenticationからコールバックを削除するだけです。

services.AddAuthentication()
    .AddFacebook(facebookOptions =>
    {
        // ...
    })
    .AddGoogle(googleOptions =>
    {
        // ...
    })
    .AddTwitter(twitterOptions =>
    {
        // ...
    })
    .AddMicrosoftAccount(microsoftOptions =>
    {
        // ...
    });

また、冗長なAddCookieの呼び出しも削除しました。これによりCookies認証スキームが追加されますが、すでに説明したように、アプリケーションはIdentity.Applicationを使用しています。

2
Kirk Larkin

「startup.cs」でミドルウェアの順番を変えてみてください。したがって、次のようにapp.UseHttpsRedirection()の前にapp.UseAuthentication()を使用する必要があります。

    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
0