Авторизованная страница перенаправляет обратно на страницу входа после успешного входа - PullRequest
0 голосов
/ 23 ноября 2018

У меня есть простое приложение asp.net-core, использующее версию 2.1.HomeController имеет страницу с авторизованным атрибутом.Когда я нажимаю на страницу «О программе», для которой требуется авторизация, я попадаю на страницу входа в систему и после ввода моего имени пользователя и пароля происходит следующее:

  • пользователь успешно вошел в систему
  • пользовательперенаправляется в / Home / About
  • HomeController.About метод вызывается в отладчике, и представление About обслуживается.
  • Каким-то образом пользователь перенаправляется обратно на AccountController.Login
  • , когда пользователь вошел в систему, так что теперь я могу перейти на любую страницу, требующую авторизации.

Я пробовал это также с Chrome и Edge.Я могу воспроизвести ошибку с обоими браузерами.

Я создал небольшой проект репро, который воспроизводит проблему на моем компьютере и настройке.

Portfolio_Authentication

Следующие шаги, которые я использую для воспроизведения проблемы:

  1. Регистрация пользователя на сайте
  2. Выйдите из системы, если пользователь вошел в систему.
  3. Нажмите на ссылку меню About в заголовке.
  4. Введите имя пользователя и пароль
  5. Обратите внимание, что аутентификация в порядке, поскольку имя пользователя отображается в верхней правой части экрана, но имя входа не перенаправляется на страницу О программе.

Мне интересно, почему это происходит и как это исправить?Спасибо за помощь.Все отзывы приветствуются.

HomeController:

public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    [Authorize]
    public IActionResult About()
    {
        ViewData["Message"] = "Your application description page.";

        return View();
    } 
}

Мой 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.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        // services.AddAuthentication();
        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(options =>
                {
                    options.LoginPath = "/Account/LogIn";
                    options.LogoutPath = "/Account/LogOff";
                });

        // Add application services.
        services.AddTransient<IEmailSender, EmailSender>();

        services.AddMvc()
                .AddFeatureFolders(); // .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); ;
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseBrowserLink();
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseStaticFiles();

        app.UseAuthentication();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

и этот журнал я вижу в моем окне выводав Visual Studio:

Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (1ms) [Parameters=[@__normalizedUserName_0='?' (Size = 256)], CommandType='Text', CommandTimeout='30']
SELECT TOP(1) [u].[Id], [u].[AccessFailedCount], [u].[ConcurrencyStamp], [u].[Email], [u].[EmailConfirmed], [u].[LockoutEnabled], [u].[LockoutEnd], [u].[NormalizedEmail], [u].[NormalizedUserName], [u].[PasswordHash], [u].[PhoneNumber], [u].[PhoneNumberConfirmed], [u].[SecurityStamp], [u].[TwoFactorEnabled], [u].[UserName]
FROM [AspNetUsers] AS [u]
WHERE [u].[NormalizedUserName] = @__normalizedUserName_0
Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (2ms) [Parameters=[@__user_Id_0='?' (Size = 450)], CommandType='Text', CommandTimeout='30']
SELECT [uc].[Id], [uc].[ClaimType], [uc].[ClaimValue], [uc].[UserId]
FROM [AspNetUserClaims] AS [uc]
WHERE [uc].[UserId] = @__user_Id_0
Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (1ms) [Parameters=[@__userId_0='?' (Size = 450)], CommandType='Text', CommandTimeout='30']
SELECT [role].[Name]
FROM [AspNetUserRoles] AS [userRole]
INNER JOIN [AspNetRoles] AS [role] ON [userRole].[RoleId] = [role].[Id]
WHERE [userRole].[UserId] = @__userId_0
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: Identity.Application signed in.
Portfolio.Features.Account.AccountController:Information: User logged in.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action method Portfolio.Features.Account.AccountController.Login (Portfolio), returned result Microsoft.AspNetCore.Mvc.RedirectResult in 32.6215ms.
Microsoft.AspNetCore.Mvc.Infrastructure.RedirectResultExecutor:Information: Executing RedirectResult, redirecting to /Home/About.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action Portfolio.Features.Account.AccountController.Login (Portfolio) in 41.5571ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 49.3022ms 302 
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:44392/Home/About  
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "About", controller = "Home"}. Executing action Portfolio.Features.Home.HomeController.About (Portfolio)
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization was successful.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executing action method Portfolio.Features.Home.HomeController.About (Portfolio) - Validation state: Valid
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action method Portfolio.Features.Home.HomeController.About (Portfolio), returned result Microsoft.AspNetCore.Mvc.ViewResult in 2212.7896ms.
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor:Information: Executing ViewResult, running view About.
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor:Information: Executed ViewResult - view About executed in 3.1424ms.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action Portfolio.Features.Home.HomeController.About (Portfolio) in 2225.297ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 2233.0907ms 200 text/html; charset=utf-8
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:44392/Account/Login?ReturnUrl=%2FHome%2FAbout  
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "Login", controller = "Account"}. Executing action Portfolio.Features.Account.AccountController.Login (Portfolio)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executing action method Portfolio.Features.Account.AccountController.Login (Portfolio) with arguments (/Home/About) - Validation state: Valid
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: Identity.External signed out.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action method Portfolio.Features.Account.AccountController.Login (Portfolio), returned result Microsoft.AspNetCore.Mvc.ViewResult in 1528.1878ms.
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor:Information: Executing ViewResult, running view Login.
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor:Information: Executed ViewResult - view Login executed in 5.8984ms.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action Portfolio.Features.Account.AccountController.Login (Portfolio) in 1543.8386ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 1553.3133ms 200 text/html; charset=utf-8
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:44392/lib/bootstrap/dist/css/bootstrap.css  
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:44392/css/site.css  
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware:Information: Sending file. Request path: '/css/site.css'. Physical path: 'C:\dev\web\portfolio-variants\Portfolio_Controller_V2\Portfolio\wwwroot\css\site.css'
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware:Information: Sending file. Request path: '/lib/bootstrap/dist/css/bootstrap.css'. Physical path: 'C:\dev\web\portfolio-variants\Portfolio_Controller_V2\Portfolio\wwwroot\lib\bootstrap\dist\css\bootstrap.css'
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 28.4192ms 200 text/css
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 41.4384ms 200 text/css

Ответы [ 2 ]

0 голосов
/ 27 ноября 2018

В вашем проекте Github у вас есть файл site.js, который содержит (помимо прочего) следующий обработчик событий jQuery:

$('form[method=post]').not('.no-ajax').on('submit', function () {
    ...

    $.ajax({
        url: $this.attr('action'),
        ...
        statusCode: {
            200: redirect
        },
        ...
    }).error(highlightErrors);

    return false;
}

Когда вы отправляете свою форму входа, вы в конечном итоге запускаетечерез этот блок кода выше, который затем вызывает вашу функцию обратного вызова redirect для statusCode из 200, показанную ниже:

var redirect = function (data) {
    if (data.redirect) {
        window.location = data.redirect;
    } else {
        window.scrollTo(0, 0);
        window.location.reload();
    }
};

В описанном вами сценарии data.redirectundefined.В этом случае вы в конечном итоге звоните window.location.reload(), что, разумеется, перезагружает страницу входа в систему и ясно объясняет проблему, с которой вы столкнулись.

Вот пошаговое описание того, что происходит:

  1. Событие отправки вызывается при нажатии кнопки «Войти».
  2. Перехват POST на основе браузера пересылается вместо в виде XHR-запроса.
  3. Сервер входит в систему пользователя, назначает cookie и возвращает ответ 302 для перенаправления на /Home/About.
  4. Внутренняя механика XHR следует за перенаправлением и опускает HTML-код для /Home/Aboutpage.
  5. Ваш обратный вызов Javascript redirect вызывается там, где data представляет ответ на страницу /Home/About (ответ text/html).
  6. Наконец, пока ещена странице /Account/Login страница перезагружается, как описано выше.

Из-за того, как вы настроили селектор jQuery, показанный в первом фрагменте кода, вы можете просто добавитьno-ajax класс к вашей форме входа, и он будет вести себяожидается.

0 голосов
/ 23 ноября 2018

Вы также должны вызвать services.AddAuthentication в методе ConfigureServices в файле запуска.

Вызов AddAuthentication должен быть настроен в соответствии с потребностями вашего приложения.(Cookie, внешние входы в систему и т.2,0 . * * 1 010

...