it-swarm.com.de

ASP.NET Core 2.0 deaktiviert die automatische Abfrage

Nach dem Upgrade meines ASP.NET Core-Projekts auf 2.0 geben Versuche, auf geschützte Endpunkte zuzugreifen, nicht mehr 401 zurück, sondern werden an einen (nicht vorhandenen) Endpunkt umgeleitet, um den Benutzer die Authentifizierung zu ermöglichen.

Das gewünschte Verhalten ist, dass die Anwendung einfach eine 401 zurückgibt. Früher würde ich AutomaticChallenge = false beim Konfigurieren der Authentifizierung festlegen, aber gemäß diesem Artikel ist die Einstellung nicht mehr relevant (tatsächlich existiert sie nicht mehr).

Meine Authentifizierung ist wie folgt konfiguriert:

Startup.cs.ConfigureServices ():

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(o =>
                {
                    o.Cookie.Name = options.CookieName;
                    o.Cookie.Domain = options.CookieDomain;
                    o.SlidingExpiration = true;
                    o.ExpireTimeSpan = options.CookieLifetime;
                    o.TicketDataFormat = ticketFormat;
                    o.CookieManager = new CustomChunkingCookieManager();
                });

Konfigurieren():

app.UseAuthentication();

Wie kann ich die automatische Abfrage deaktivieren, damit die Anwendung 401 zurückgibt, wenn der Benutzer nicht authentifiziert ist?

14
severin

Wie in einigen anderen Antworten darauf hingewiesen wurde, gibt es keine Einstellung mehr, um die automatische Abfrage mit Cookie-Authentifizierung zu deaktivieren. Die Lösung besteht darin, OnRedirectToLogin zu überschreiben:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddCookie(options =>
         {                 
             options.Events.OnRedirectToLogin = context =>
             {
                 context.Response.Headers["Location"] = context.RedirectUri;
                 context.Response.StatusCode = 401;
                 return Task.CompletedTask;
             };
         });

Dies kann sich in der Zukunft ändern: https://github.com/aspnet/Security/issues/1394

22
severin

Nach einiger Recherche fand ich heraus, dass wir dieses Problem mit dem folgenden Ansatz lösen können:

Wir können zwei Authentifizierungsschemas hinzufügen, sowohl Identität als auch JWT. Wenn Sie das Identitätsschema für die Authentifizierung verwenden und das JWT-Schema für die Abfrage verwenden, leitet JWT während der Abfrage keine Anmelderoute weiter.

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

services.AddAuthentication((cfg =>
{
    cfg.DefaultScheme = IdentityConstants.ApplicationScheme;
    cfg.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})).AddJwtBearer();
19
Zheng Xing

Ähnlich wie bei @Serverin hat sich das Setzen des OnRedirectToLogin des Anwendungscookies als erfolgreich erwiesen, muss jedoch in folgenden Anweisungen ausgeführt werden:

services.ConfigureApplicationCookie(options => {
  options.Events.OnRedirectToLogin = context => {
    context.Response.Headers["Location"] = context.RedirectUri;
    context.Response.StatusCode = 401;
    return Task.CompletedTask;
  };
});
4
sammarcow

Nach diesem Artikel:

In 1.x sollten die Eigenschaften AutomaticAuthenticate und AutomaticChallenge für ein einziges Authentifizierungsschema festgelegt werden. Es gab keine gute Möglichkeit, dies durchzusetzen.

In 2.0 wurden diese beiden Eigenschaften als Flags für die einzelne AuthenticationOptions -Instanz entfernt und in die Basis-AuthenticationOptions-Klasse verschoben. Die Eigenschaften können im Aufruf der Methode AddAuthentication innerhalb der Methode ConfigureServices von Startup.cs konfiguriert werden

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);

Verwenden Sie alternativ eine überladene Version der AddAuthentication-Methode, um mehr als eine Eigenschaft festzulegen. Im folgenden Beispiel für eine überladene Methode wird das Standardschema auf CookieAuthenticationDefaults.AuthenticationScheme festgelegt. Das Authentifizierungsschema kann alternativ in Ihren individuellen [Authorize] -Attributen oder Berechtigungsrichtlinien angegeben werden.

services.AddAuthentication(options => {
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
});

Definieren Sie ein Standardschema in 2.0, wenn eine der folgenden Bedingungen erfüllt ist:

  • Sie möchten, dass der Benutzer automatisch angemeldet wird
  • Sie verwenden das Attribut [Authorize] oder die Berechtigungsrichtlinien, ohne Schemas anzugeben

Eine Ausnahme von dieser Regel ist die AddIdentity -Methode. Diese Methode fügt Cookies für Sie hinzu und setzt die Standardauthentifizierungs- und -herausforderungsschemata auf das Anwendungscookie IdentityConstants.ApplicationScheme. Darüber hinaus wird das Standardanmeldeschema für das externe Cookie IdentityConstants.ExternalScheme festgelegt.

Hoffe das hilft dir.

4
Sergey

Dies ist der Quellcode von CookieAuthenticationEvents.OnRedirectToLogin:

public Func<RedirectContext<CookieAuthenticationOptions>, Task> OnRedirectToLogin { get; set; } = context =>
{
    if (IsAjaxRequest(context.Request))
    {
        context.Response.Headers["Location"] = context.RedirectUri;
        context.Response.StatusCode = 401;
    }
    else
    {
        context.Response.Redirect(context.RedirectUri);
    }
    return Task.CompletedTask;
};

Sie können der Anforderung den Header "X-Requested-With: XMLHttpRequest" hinzufügen, während Sie von Ihrem Client aus API-Aufrufe ausführen.

3
Zack

Eine andere Möglichkeit, dies zu tun, ist die Verwendung von AuthenticationSchemeOptions.EventsType (Eine andere Antwort zeigt hier darauf ). Auf diese Weise können Sie andere Komponenten in den Auflösungsprozess einbeziehen.

Hier ist ein Beispiel einschließlich Registrierung und Lösung, bei dem die Standardumleitung zum Anmelden bei einer nicht authentifizierten Anforderung gestoppt wird und stattdessen nur mit einem harten 401 Zurückgegeben wird. Es hat auch einen Steckplatz für andere Abhängigkeiten, die möglicherweise über nicht authentifizierte Anforderungen informiert werden müssen.

In Startup.cs:

services
    .AddAuthentication("MyAuthScheme")
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
    {
        options.EventsType = typeof(MyEventsWrapper);
    };

...

services.AddTransient<MyEventsWrapper>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

Dann in MyEventsWrapper.cs:

public class MyEventsWrapper : CookieAuthenticationEvents
{
    private readonly IHttpContextAccessor _accessor;
    private readonly IDependency _otherDependency;

    public MyEventsWrapper(IHttpContextAccessor accessor,
                           IDependency otherDependency)
    {
        _accessor = accessor;
        _otherDependency = otherDependency;
    }

    public override async Task RedirectToLogin(RedirectContext<CookieAuthenticationOptions> context)
    {
        context.Response.Headers.Remove("Location");
        context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        await _otherDependency.Cleanup(_accessor.HttpContext);
    }
}
1
eouw0o83hf

Ich fand, dass in den meisten Fällen die Lösung zu überschreiben ist

OnRedirectToLogin

Aber in meiner App habe ich mehrere Authentifizierungsrichtlinien verwendet und das Überschreiben von OnRedirectToLogin hat bei mir nicht funktioniert. In meinem Fall bestand die Lösung darin, eine einfache Middleware hinzuzufügen, um die eingehende Anfrage umzuleiten.

app.Use(async (HttpContext context, Func<Task> next) => {
    await next.Invoke(); //execute the request pipeline

    if (context.Response.StatusCode == StatusCodes.Status302Found && context.Response.Headers.TryGetValue("Location", out var redirect)) {
        var v = redirect.ToString();
        if (v.StartsWith($"{context.Request.Scheme}://{context.Request.Host}/Account/Login")) {
            context.Response.Headers["Location"] = $"{context.Request.Scheme}://{context.Request.Host}{context.Request.Path}";
            context.Response.StatusCode = 401;
        }
    }
});

1

Ich bin nicht sicher, wie Sie den 401-Fehler generieren, wenn Sie jedoch Folgendes verwenden:

o.AccessDeniedPath = "{path to invalid}";

Auf diese Weise können Sie irgendwo umleiten, wenn die Herausforderung fehlgeschlagen ist.

0
Gary Holland