Авторизация Razor Page застряла в петлях с внешним cookie - PullRequest
1 голос
/ 29 июня 2019

У меня есть приложение ASP.NET Core, которое я интегрирую с Auth0. После аутентификации я хочу перенаправить на страницу для сбора информации для создания локальной учетной записи, как это делают стандартные расширения Facebook и Google.

Я установил основной файл cookie, внешний файл cookie и точку Auth0. Затем он выполняет обратный вызов на страницу (/ Account / ExternalLogin), где я делаю вход в основной файл cookie после выполнения всего, что им нужно, и перенаправляю на страницу, требующую авторизации (/ Profile. Это все отлично работает.

Однако, если я просто попытаюсь перейти на эту страницу, а не через маршрут входа в систему, я застряну в цикле.

Я совершенно уверен, что мне не хватает только одной глупости, но, похоже, не могу ее получить.

Я старался изо всех сил понять каждую комбинацию вещей и ударил стену. Я уверен, что это что-то глупое.

Вот моя важная часть startup.cs

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        // This lambda determines whether user consent for non-essential cookies is needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    // Add authentication services
    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = "MainCookie";
        options.DefaultChallengeScheme = "Auth0";
    })
    .AddCookie("MainCookie", options =>
    {
        options.ForwardChallenge = "Auth0";
    })
    .AddCookie("External", options =>
    {
    })
    .AddOpenIdConnect("Auth0", options =>
    {
        // Set the authority to your Auth0 domain
        options.Authority = $"https://{Configuration["Auth0:Domain"]}";

        // Configure the Auth0 Client ID and Client Secret
        options.ClientId = Configuration["Auth0:ClientId"];
        options.ClientSecret = Configuration["Auth0:ClientSecret"];

        // Set response type to code
        options.ResponseType = "code";

        // Configure the scope
        options.Scope.Clear();
        options.Scope.Add("openid");
        options.Scope.Add("profile");
        options.Scope.Add("email");

        options.SignInScheme = "External";

        // Set the callback path, so Auth0 will call back to http://localhost:3000/callback
        // Also ensure that you have added the URL as an Allowed Callback URL in your Auth0 dashboard
        options.CallbackPath = new PathString("/callback");

        // Configure the Claims Issuer to be Auth0
        options.ClaimsIssuer = "Auth0";

        options.Events = new OpenIdConnectEvents
        {
            // handle the logout redirection
            OnRedirectToIdentityProviderForSignOut = (context) =>
                    {
                        var logoutUri = $"https://{Configuration["Auth0:Domain"]}/v2/logout?client_id={Configuration["Auth0:ClientId"]}";

                        var postLogoutUri = context.Properties.RedirectUri;
                        if (!string.IsNullOrEmpty(postLogoutUri))
                        {
                            if (postLogoutUri.StartsWith("/"))
                            {
                                // transform to absolute
                                var request = context.Request;
                                postLogoutUri = $"{request.Scheme}://{request.Host}{request.PathBase}{postLogoutUri}";
                            }
                            logoutUri += $"&returnTo={ Uri.EscapeDataString(postLogoutUri) }";
                        }

                        context.Response.Redirect(logoutUri);
                        context.HandleResponse();

                        return Task.CompletedTask;
                    }
        };
    });


    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            .AddRazorPagesOptions(options =>
            {
                options.Conventions.AuthorizePage("/Profile");
            });
}

Вот AccountController

public class AccountController : Controller
{
    public async Task Login(string returnUrl = "/")
    {
        var redirectUrl = Url.Page("/ExternalLogin", pageHandler: "Callback", values: new { returnUrl });
        await HttpContext.ChallengeAsync("Auth0", new AuthenticationProperties() { RedirectUri = redirectUrl });
    }

    [Authorize]
    public async Task Logout()
    {
        await HttpContext.SignOutAsync("External");
        await HttpContext.SignOutAsync("MainCookie");
        await HttpContext.SignOutAsync("Auth0", new AuthenticationProperties
        {
            RedirectUri = Url.Action("Index", "Home")
        });
    }
}

ТАК мы перенаправляем на обратный вызов ExternalLogin. В настоящее время есть только кнопка отправки, которая переходит к обратному вызову подтверждения, который завершает вход в систему. В конечном итоге это будет заменено проверкой, чтобы узнать, есть ли у меня для них учетная запись, и заставит их зарегистрироваться.

public class ExternalLoginModel : PageModel
{
    public IActionResult OnPost(string provider, string returnUrl = null)
    {
        var redirectUrl = Url.Page("./ExternalLogin", pageHandler: "Callback", values: new { returnUrl });
        return new ChallengeResult(provider, null);
    }


    public async Task<IActionResult> OnGetCallbackAsync(string returnUrl = null, string remoteError = null)
    {
        returnUrl = returnUrl ?? Url.Content("~/");
        if (remoteError != null)
        {
            ErrorMessage = $"Error from external provider: {remoteError}";
            return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
        }

        return Page();
    }

    public async Task<IActionResult> OnPostConfirmAsync()
    {
        var claimsPrincipal = await HttpContext.AuthenticateAsync("External");
        await HttpContext.SignInAsync("MainCookie", claimsPrincipal.Principal);
        await HttpContext.SignOutAsync("External");

        return RedirectToPage("/Profile");
    }

}

Поэтому, когда я захожу / Учетная запись / Вход в систему, он корректно отправляет меня в Auth0, затем в ExternalLogin, и я могу нажать кнопку и установить Основной Cookie. Это тогда позволяет мне получить доступ к /Profile.

Однако, если я еще не авторизован, если я выполняю / Profile, я затем переключаюсь на Auth0, но после аутентификации я просто застреваю в цикле, подобном этому.

Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/2.0 GET https://localhost:44375/profile  
Microsoft.AspNetCore.Routing.EndpointMiddleware:Information: Executing endpoint 'Page: /Profile'
Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker:Information: Route matched with {page = "/Profile", action = "", controller = ""}. Executing page /Profile
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed.
Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker: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.OpenIdConnect.OpenIdConnectHandler:Information: AuthenticationScheme: Auth0 was challenged.
Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker:Information: Executed page /Profile in 11.2594ms
Microsoft.AspNetCore.Routing.EndpointMiddleware:Information: Executed endpoint 'Page: /Profile'
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 28.548ms 302 
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/2.0 POST https://localhost:44375/callback application/x-www-form-urlencoded 375
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: External signed in.
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 113.1223ms 302 

1 Ответ

1 голос
/ 29 июня 2019

Изменение options.DefaultChallengeScheme = "Auth0" на options.DefaultChallengeScheme = "MainCookie" - это все, что было нужно.

...