Cookie 身份验证失败 ASP.NET Core 3.1

Cookie Authentication Fails ASP.NET Core 3.1

我没有将现有的 ASP.NET Core 2.1 项目迁移到 3.1,而是创建了一个新项目。在新项目中,SignIn(...) 控制器方法执行无误,但无法重定向到指定的操作。相反,它重定向到 AccessDeniedPath.

我的环境是 Win10 VS 2019 IIS Express 使用 Chrome。

谁能告诉我是什么原因造成的?我在 3.1 中是否遗漏或做错了什么?

PROGRAM.CS

public static void Main(string[] args)
{
    CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
            //webBuilder.UseIISIntegration();
            //webBuilder.UseKestrel();
            //webBuilder.CaptureStartupErrors(true);
            //webBuilder.UseEnvironment(Environments.Development);
        });

STARTUP.CS

    public void ConfigureServices(IServiceCollection services)
    {
        try
        {
            services.AddRazorPages()        
                .AddRazorRuntimeCompilation();

            services.AddControllersWithViews();

            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
                {
                    options.ExpireTimeSpan = new TimeSpan(30, 0, 0, 0);
                    options.LoginPath = new PathString("/Home/Index/");
                    options.AccessDeniedPath = new PathString("/Home/Index/");
                    options.LogoutPath = new PathString("/Home/Index/");
                    options.Validate();
                });

            services.Configure<Microsoft.AspNetCore.Identity.IdentityOptions>(options =>
            {
                options.Password.RequireDigit = true;
                options.Password.RequireLowercase = true;
                options.Password.RequireNonAlphanumeric = true;
                options.Password.RequireUppercase = true;
                options.Password.RequiredLength = 8;
                options.Password.RequiredUniqueChars = 1;
                options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
                options.Lockout.MaxFailedAccessAttempts = 5;
                options.Lockout.AllowedForNewUsers = true;
                options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
            });

            services.AddDetectionCore()
                .AddDevice();

            services.AddMvc();
            services.AddAntiforgery();
            services.Configure<MvcOptions>(options =>
            {
                options.Filters.Add(new RequireHttpsAttribute());
            });
        }
        catch (Exception ex)
        {
            gFunc.ProcessError(ex);
        }
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        try
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }
            app.UseStaticFiles();
            app.UseHttpsRedirection();
            app.UseRouting();
            app.UseAuthorization();
            app.UseAuthentication();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }
        catch (Exception ex)
        {
            gFunc.ProcessError(ex);
        }
    }

CONTROLLER.CS

    [HttpPost()]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> SignIn(SignIn sin)
    {
        bool is_err = false;
        try
        {
            // check data
            if (string.IsNullOrEmpty(sin.EmailAddress))
            {
                is_err = true;
                ModelState.AddModelError("Samadhi", "Missing email address.");
            }
            if (string.IsNullOrEmpty(sin.Password))
            {
                is_err = true;
                ModelState.AddModelError("Samadhi", "Missing password.");
            }

            // check authorisation
            if (ModelState.IsValid && !is_err)
            {
                sin = await RepoSamadhi.ShopSignIn(sin);
                if (sin.ShopID == 0 || sin.IsValidationFail || string.IsNullOrEmpty(sin.ShopToken))
                {
                    is_err = true;
                    ModelState.AddModelError("Samadhi", "Account not found. Check your credentials.");
                }
            }

            // check model state
            if (!ModelState.IsValid || is_err)
            {
                sin.IsSignInFailed = true;
                return View("SignIn", sin);
            }

            // create claims
            var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Sid, sin.ShopToken),
            new Claim(ClaimTypes.NameIdentifier, sin.ShopID.ToString()),
            new Claim(ClaimTypes.Email, sin.EmailAddress.ToLower()),
            new Claim(ClaimTypes.Role, "SamadhiShop")
        };

            // create identity
            var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); 

            // create principal
            ClaimsPrincipal principal = new ClaimsPrincipal(new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme));

            var authProperties = new AuthenticationProperties
            {
                IsPersistent = true // sin.RememberMe
            };

            // sign-in
            await HttpContext.SignInAsync(scheme: CookieAuthenticationDefaults.AuthenticationScheme, principal: principal, properties: authProperties);
        }
        catch (Exception ex)
        {
            gFunc.ProcessError(ex);
        }
        return RedirectToAction("Console", new { date = DateTime.Today.ToString("d MMM yyyy"), timer = false });
    }

    [HttpGet]
    [Authorize]
    public async Task<ActionResult> Console(string date, bool timer)
    {
        int shop_id = int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value);
        string token = User.FindFirst(ClaimTypes.Sid).Value;

        DateTime dt = DateTime.Parse(date);
        Shop ss = await RepoSamadhi.GetShop(shop_id, token, dt);
        ss.IsTimerOn = timer;
        return View((_device.Type == DeviceType.Mobile) ? "ConsoleM" : "ConsoleM", ss);
    }

你的中间件顺序错了,正确的顺序应该是

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