У меня есть веб-приложение MVC .NET Core 1.1, использующее удостоверения для управления пользователями.
После успешного входа я перенаправляю пользователя на домашнюю страницу. Этот контроллер имеет атрибут [Authorize], но когда он пытается загрузить страницу, я перенаправляюсь на страницу входа, и в моем окне отладки появляется следующая ошибка
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:64496/
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed for user: (null).
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes ().
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware:Information: AuthenticationScheme: Identity.Application was challenged.
Кажется, что мой объект User потерян после входа в систему.
Этот код работает на Azure просто отлично и работал для меня 6 месяцев назад локально, когда я сделал последнее изменение. Сегодня я открыл решение, чтобы посмотреть на проблему, о которой сообщили клиенты, и теперь я не могу войти. Там не было никаких изменений кода, но я обновил VS и .net на моей машине. Мне интересно, могут ли эти обновления быть причиной.
Контроллер входа
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation(1, "User logged in.");
return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning(2, "User account locked out.");
return View("Lockout");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Класс запуска
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.Configure<FormOptions>(x => x.ValueCountLimit = 5000);
services.AddDbContext<DBContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DBContext")));
services.AddIdentity<User, Role>()
.AddEntityFrameworkStores<DBContext>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>(options =>
{
// Password settings
options.Password.RequireDigit = false;
options.Password.RequiredLength = 6;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
// Lockout settings
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
options.Lockout.MaxFailedAccessAttempts = 10;
// Cookie settings
options.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromDays(30);
options.Cookies.ApplicationCookie.LoginPath = "/Users/Account/LogIn";
options.Cookies.ApplicationCookie.LogoutPath = "/Users/Account/LogOff";
options.Cookies.ApplicationCookie.AccessDeniedPath = "/Users/Account/AccessDenied";
// User settings
options.User.RequireUniqueEmail = true;
});
services.Configure<DataProtectionTokenProviderOptions>(options =>
{
//set all tokens to expire in 30 days. Default is 1 day and for new accounts that seems to be too short
options.TokenLifespan = TimeSpan.FromDays(30);
});
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
// Adds a default in-memory implementation of IDistributedCache for sessions
// more info here: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/app-state
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
// Set a short timeout for easy testing.
//options.IdleTimeout = TimeSpan.FromSeconds(10);
options.CookieHttpOnly = true;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
loggerFactory.AddAzureWebAppDiagnostics();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Shared/Error");
}
app.UseStatusCodePagesWithReExecute("/Shared/Error/{0}");
app.UseStaticFiles();
app.UseIdentity();
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "areaRoute",
template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
SeedData.Initialize(app.ApplicationServices);
}
}