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();
我没有将现有的 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();