Autorisieren mit einem bestimmten Schema in ASP.NET Core

Eine Einführung in Authentifizierungsschemas in ASP.NET Core finden Sie unter Authentifizierungsschema.

In einigen Szenarien wie bei Single-Page-Apps (SPAs) ist es üblich, mehrere Authentifizierungsmethoden zu verwenden. Beispielsweise kann die App die cookie-basierte Authentifizierung für die Anmeldung und die Authentifizierung mit JWT-Bearer für JavaScript-Anforderungen verwenden. In einigen Fällen verfügt die App möglicherweise über mehrere Instanzen eines Authentifizierungshandlers. Beispiel: zwei cookie-Handler, von denen einer eine grundlegende Identität enthält, und einer erstellt wird, wenn eine Multi-Faktor-Authentifizierung (MFA) ausgelöst wurde. MFA kann ausgelöst werden, da Benutzer*innen einen Vorgang anfordern, der zusätzliche Sicherheit erfordert. Weitere Informationen zum Erzwingen von MFA, wenn Benutzer*innen eine Ressource anfordern, die MFA erfordert, finden Sie im GitHub-Issue Protect section with MFA (Schützen eines Abschnitts mit MFA).

Wenn der Authentifizierungsdienst während der Authentifizierung konfiguriert wird, wird ein Authentifizierungsschema benannt. Beispiel:

using Microsoft.AspNetCore.Authentication;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication()
        .AddCookie(options =>
        {
            options.LoginPath = "/Account/Unauthorized/";
            options.AccessDeniedPath = "/Account/Forbidden/";
        })
        .AddJwtBearer(options =>
        {
            options.Audience = "http://localhost:5001/";
            options.Authority = "http://localhost:5000/";
        });

builder.Services.AddAuthentication()
        .AddIdentityServerJwt();

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.MapFallbackToFile("index.html");

app.Run();

Im vorstehenden Code wurden zwei Authentifizierungshandler hinzugefügt: einer für cookies und einer für den Bearer.

Hinweis

Wenn Sie das Standardschema angeben, wird die HttpContext.User-Eigenschaft auf diese Identität festgelegt. Ist dieses Verhalten nicht erwünscht, können Sie es deaktivieren, indem Sie die parameterlose Form von AddAuthentication aufrufen.

Auswählen des Schemas mit dem Authorize-Attribut

Bei der Autorisierung gibt die App den zu verwendenden Handler an. Wählen Sie den Handler aus, mit dem die App die Autorisierung durch Übergeben einer durch Trennzeichen getrennten Liste von Authentifizierungsschemas an [Authorize] durchführen soll. Das [Authorize]-Attribut gibt die zu verwendenden Authentifizierungsschemas an, unabhängig davon, ob ein Standard konfiguriert wurde. Beispiel:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc;

namespace AuthScheme.Controllers;

[Authorize(AuthenticationSchemes = AuthSchemes)]
public class MixedController : Controller
{
    private const string AuthSchemes =
        CookieAuthenticationDefaults.AuthenticationScheme + "," +
        JwtBearerDefaults.AuthenticationScheme;
    public ContentResult Index() => Content(MyWidgets.GetMyContent());

}

Im vorstehenden Beispiel werden sowohl das cookie als auch die Bearerhandler ausgeführt und können eine Identität für den/die aktuelle/n Benutzer*in erstellen und anfügen. Durch Angeben eines einzigen Schemas wird der entsprechende Handler ausgeführt:

[Authorize(AuthenticationSchemes=JwtBearerDefaults.AuthenticationScheme)]
public class Mixed2Controller : Controller
{
    public ContentResult Index() => Content(MyWidgets.GetMyContent());
}

Im vorstehenden Code wird nur der Handler mit dem Schema „Bearer“ ausgeführt. Alle cookie-basierten Identitäten werden ignoriert.

Auswählen des Schemas mit Richtlinien

Wenn Sie die gewünschten Schemas bevorzugt in der Richtlinie angeben möchten, können Sie beim Hinzufügen einer Richtlinie die Sammlung AuthenticationSchemes festlegen:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("Over18", policy =>
    {
        policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
        policy.RequireAuthenticatedUser();
        policy.Requirements.Add(new MinimumAgeRequirement(18));
    });
});

builder.Services.AddAuthentication()
                .AddIdentityServerJwt();

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.MapFallbackToFile("index.html");

app.Run();

Im vorstehenden Beispiel wird die Richtlinie „Over18“ nur für die vom Bearerhandler erstellte Identität ausgeführt. Verwenden Sie die Richtlinie, indem Sie die [Authorize]-Eigenschaft des Policy-Attributs festlegen:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace AuthScheme.Controllers;
[Authorize(Policy = "Over18")]
public class RegistrationController : Controller
{
    // Do Registration

Verwenden mehrerer Authentifizierungsschemas

Einige Apps müssen möglicherweise mehrere Authentifizierungstypen unterstützen. Beispielsweise könnte Ihre App Benutzer*innen aus Azure Active Directory und aus einer Datenbank authentifizieren. Ein anderes Beispiel ist eine App, die Benutzer*innen sowohl von Active Directory-Verbunddienste (AD FS) als auch von Azure Active Directory B2C authentifiziert. In diesem Fall sollte die App ein JWT-Bearertoken von mehreren Ausstellern akzeptieren.

Fügen Sie alle Authentifizierungsschemas hinzu, die Sie akzeptieren möchten. Der folgende Code fügt beispielsweise zwei JWT-Bearerauthentifizierungsschemas mit unterschiedlichen Ausstellern hinzu:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;

var builder = WebApplication.CreateBuilder(args);

// Authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.Audience = "https://localhost:5000/";
            options.Authority = "https://localhost:5000/identity/";
        })
        .AddJwtBearer("AzureAD", options =>
        {
            options.Audience = "https://localhost:5000/";
            options.Authority = "https://login.microsoftonline.com/eb971100-7f436/";
        });

// Authorization
builder.Services.AddAuthorization(options =>
{
    var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(
        JwtBearerDefaults.AuthenticationScheme,
        "AzureAD");
    defaultAuthorizationPolicyBuilder =
        defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
    options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
});

builder.Services.AddAuthentication()
        .AddIdentityServerJwt();

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.MapFallbackToFile("index.html");

app.Run();

Hinweis

Beim Standardauthentifizierungsschema JwtBearerDefaults.AuthenticationScheme wird nur eine JWT-Bearerauthentifizierung registriert. Zusätzliche Authentifizierungsmethoden müssen mit einem eindeutigen Authentifizierungsschema registriert werden.

Aktualisieren Sie die Standardautorisierungsrichtlinie, um beide Authentifizierungsschemas zu akzeptieren. Beispiel:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;

var builder = WebApplication.CreateBuilder(args);

// Authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.Audience = "https://localhost:5000/";
            options.Authority = "https://localhost:5000/identity/";
        })
        .AddJwtBearer("AzureAD", options =>
        {
            options.Audience = "https://localhost:5000/";
            options.Authority = "https://login.microsoftonline.com/eb971100-7f436/";
        });

// Authorization
builder.Services.AddAuthorization(options =>
{
    var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(
        JwtBearerDefaults.AuthenticationScheme,
        "AzureAD");
    defaultAuthorizationPolicyBuilder =
        defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
    options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
});

builder.Services.AddAuthentication()
        .AddIdentityServerJwt();

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.MapFallbackToFile("index.html");

app.Run();

Da die Standardautorisierungsrichtlinie außer Kraft gesetzt wird, kann das [Authorize]-Attribut in Controllern verwendet werden. Der Controller akzeptiert dann Anforderungen mit JWT, die vom ersten oder zweiten Aussteller ausgestellt wurden.

Hinweise zum Verwenden mehrerer Authentifizierungsschemas finden Sie in diesem GitHub-Issue.

Im folgenden Beispiel werden Azure Active Directory B2C und ein anderer Azure Active Directory-Mandant verwendet:

using Microsoft.AspNetCore.Authentication;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Net.Http.Headers;
using System.IdentityModel.Tokens.Jwt;

var builder = WebApplication.CreateBuilder(args);

// Authentication
builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = "B2C_OR_AAD";
    options.DefaultChallengeScheme = "B2C_OR_AAD";
})
.AddJwtBearer("B2C", jwtOptions =>
{
    jwtOptions.MetadataAddress = "B2C-MetadataAddress";
    jwtOptions.Authority = "B2C-Authority";
    jwtOptions.Audience = "B2C-Audience";
})
.AddJwtBearer("AAD", jwtOptions =>
{
    jwtOptions.MetadataAddress = "AAD-MetadataAddress";
    jwtOptions.Authority = "AAD-Authority";
    jwtOptions.Audience = "AAD-Audience";
    jwtOptions.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateIssuerSigningKey = true,
        ValidAudiences = builder.Configuration.GetSection("ValidAudiences").Get<string[]>(),
        ValidIssuers = builder.Configuration.GetSection("ValidIssuers").Get<string[]>()
    };
})
.AddPolicyScheme("B2C_OR_AAD", "B2C_OR_AAD", options =>
{
    options.ForwardDefaultSelector = context =>
    {
        string authorization = context.Request.Headers[HeaderNames.Authorization];
        if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith("Bearer "))
        {
            var token = authorization.Substring("Bearer ".Length).Trim();
            var jwtHandler = new JwtSecurityTokenHandler();

            return (jwtHandler.CanReadToken(token) && jwtHandler.ReadJwtToken(token).Issuer.Equals("B2C-Authority"))
                ? "B2C" : "AAD";
        }
        return "AAD";
    };
});

builder.Services.AddAuthentication()
        .AddIdentityServerJwt();

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();

app.MapDefaultControllerRoute().RequireAuthorization();
app.MapRazorPages().RequireAuthorization();

app.MapFallbackToFile("index.html");

app.Run();

Im vorstehenden Code wird mit ForwardDefaultSelector ein Standardschema für die aktuelle Anforderung ausgewählt, an das Authentifizierungshandler standardmäßig alle Authentifizierungsvorgänge weiterleiten sollen. Die Standardweiterleitungslogik überprüft zuerst die genaueste Einstellung für ForwardAuthenticate, ForwardChallenge, ForwardForbid, ForwardSignIn und ForwardSignOut, dann ForwardDefaultSelector und dann ForwardDefault. Das erste Ergebnis ungleich NULL wird als Zielschema verwendet, an das weitergeleitet werden soll. Weitere Informationen finden Sie unter Richtlinienschemas in ASP.NET Core.

Eine Einführung in Authentifizierungsschemas in ASP.NET Core finden Sie unter Authentifizierungsschema.

In einigen Szenarien wie bei Single-Page-Apps (SPAs) ist es üblich, mehrere Authentifizierungsmethoden zu verwenden. Beispielsweise kann die App die cookie-basierte Authentifizierung für die Anmeldung und die Authentifizierung mit JWT-Bearer für JavaScript-Anforderungen verwenden. In einigen Fällen verfügt die App möglicherweise über mehrere Instanzen eines Authentifizierungshandlers. Beispiel: zwei cookie-Handler, von denen einer eine grundlegende Identität enthält, und einer erstellt wird, wenn eine Multi-Faktor-Authentifizierung (MFA) ausgelöst wurde. MFA kann ausgelöst werden, da Benutzer*innen einen Vorgang anfordern, der zusätzliche Sicherheit erfordert. Weitere Informationen zum Erzwingen von MFA, wenn Benutzer*innen eine Ressource anfordern, die MFA erfordert, finden Sie im GitHub-Issue Protect section with MFA (Schützen eines Abschnitts mit MFA).

Wenn der Authentifizierungsdienst während der Authentifizierung konfiguriert wird, wird ein Authentifizierungsschema benannt. Beispiel:

public void ConfigureServices(IServiceCollection services)
{
    // Code omitted for brevity

    services.AddAuthentication()
        .AddCookie(options => {
            options.LoginPath = "/Account/Unauthorized/";
            options.AccessDeniedPath = "/Account/Forbidden/";
        })
        .AddJwtBearer(options => {
            options.Audience = "http://localhost:5001/";
            options.Authority = "http://localhost:5000/";
        });

Im vorstehenden Code wurden zwei Authentifizierungshandler hinzugefügt: einer für cookies und einer für den Bearer.

Hinweis

Wenn Sie das Standardschema angeben, wird die HttpContext.User-Eigenschaft auf diese Identität festgelegt. Ist dieses Verhalten nicht erwünscht, können Sie es deaktivieren, indem Sie die parameterlose Form von AddAuthentication aufrufen.

Auswählen des Schemas mit dem Authorize-Attribut

Bei der Autorisierung gibt die App den zu verwendenden Handler an. Wählen Sie den Handler aus, mit dem die App die Autorisierung durch Übergeben einer durch Trennzeichen getrennten Liste von Authentifizierungsschemas an [Authorize] durchführen soll. Das [Authorize]-Attribut gibt die zu verwendenden Authentifizierungsschemas an, unabhängig davon, ob ein Standard konfiguriert wurde. Beispiel:

[Authorize(AuthenticationSchemes = AuthSchemes)]
public class MixedController : Controller
    // Requires the following imports:
    // using Microsoft.AspNetCore.Authentication.Cookies;
    // using Microsoft.AspNetCore.Authentication.JwtBearer;
    private const string AuthSchemes =
        CookieAuthenticationDefaults.AuthenticationScheme + "," +
        JwtBearerDefaults.AuthenticationScheme;

Im vorstehenden Beispiel werden sowohl das cookie als auch die Bearerhandler ausgeführt und können eine Identität für den/die aktuelle/n Benutzer*in erstellen und anfügen. Durch Angeben eines einzigen Schemas wird der entsprechende Handler ausgeführt.

[Authorize(AuthenticationSchemes = 
    JwtBearerDefaults.AuthenticationScheme)]
public class MixedController : Controller

Im vorstehenden Code wird nur der Handler mit dem Schema „Bearer“ ausgeführt. Alle cookie-basierten Identitäten werden ignoriert.

Auswählen des Schemas mit Richtlinien

Wenn Sie die gewünschten Schemas bevorzugt in der Richtlinie angeben möchten, können Sie beim Hinzufügen der Richtlinie die Sammlung AuthenticationSchemes festlegen:

services.AddAuthorization(options =>
{
    options.AddPolicy("Over18", policy =>
    {
        policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
        policy.RequireAuthenticatedUser();
        policy.Requirements.Add(new MinimumAgeRequirement());
    });
});

Im vorstehenden Beispiel wird die Richtlinie „Over18“ nur für die vom Bearerhandler erstellte Identität ausgeführt. Verwenden Sie die Richtlinie, indem Sie die [Authorize]-Eigenschaft des Policy-Attributs festlegen:

[Authorize(Policy = "Over18")]
public class RegistrationController : Controller

Verwenden mehrerer Authentifizierungsschemas

Einige Apps müssen möglicherweise mehrere Authentifizierungstypen unterstützen. Beispielsweise könnte Ihre App Benutzer*innen aus Azure Active Directory und aus einer Datenbank authentifizieren. Ein anderes Beispiel ist eine App, die Benutzer*innen sowohl von Active Directory-Verbunddienste (AD FS) als auch von Azure Active Directory B2C authentifiziert. In diesem Fall sollte die App ein JWT-Bearertoken von mehreren Ausstellern akzeptieren.

Fügen Sie alle Authentifizierungsschemas hinzu, die Sie akzeptieren möchten. Der folgende Code in Startup.ConfigureServices fügt beispielsweise zwei JWT-Bearerauthentifizierungsschemas mit unterschiedlichen Ausstellern hinzu:

public void ConfigureServices(IServiceCollection services)
{
    // Code omitted for brevity

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.Audience = "https://localhost:5000/";
            options.Authority = "https://localhost:5000/identity/";
        })
        .AddJwtBearer("AzureAD", options =>
        {
            options.Audience = "https://localhost:5000/";
            options.Authority = "https://login.microsoftonline.com/eb971100-6f99-4bdc-8611-1bc8edd7f436/";
        });
}

Hinweis

Beim Standardauthentifizierungsschema JwtBearerDefaults.AuthenticationScheme wird nur eine JWT-Bearerauthentifizierung registriert. Zusätzliche Authentifizierungsmethoden müssen mit einem eindeutigen Authentifizierungsschema registriert werden.

Aktualisieren Sie als nächsten Schritt die Standardautorisierungsrichtlinie, um beide Authentifizierungsschemas zu akzeptieren. Beispiel:

public void ConfigureServices(IServiceCollection services)
{
    // Code omitted for brevity

    services.AddAuthorization(options =>
    {
        var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(
            JwtBearerDefaults.AuthenticationScheme,
            "AzureAD");
        defaultAuthorizationPolicyBuilder = 
            defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
        options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
    });
}

Da die Standardautorisierungsrichtlinie außer Kraft gesetzt wird, kann das [Authorize]-Attribut in Controllern verwendet werden. Der Controller akzeptiert dann Anforderungen mit JWT, die vom ersten oder zweiten Aussteller ausgestellt wurden.

Hinweise zum Verwenden mehrerer Authentifizierungsschemas finden Sie in diesem GitHub-Issue.