Autorizace s využitím konkrétního schématu v ASP.NET Core

Úvod do schémat ověřování v ASP.NET Core najdete v tématu Schéma ověřování.

V některých scénářích, jako jsou jednostráňové aplikace (SPA), je běžné používat více metod ověřování. Aplikace může například použít cookieověřování na základě přihlašovacích údajů a ověřování nosných certifikátů JWT pro požadavky JavaScriptu. V některých případech může mít aplikace více instancí obslužné rutiny ověřování. Například dva cookie obslužné rutiny, kde jeden obsahuje základní identitu a jeden se vytvoří při aktivaci vícefaktorového ověřování (MFA). Vícefaktorové ověřování se může aktivovat, protože uživatel požádal o operaci, která vyžaduje dodatečné zabezpečení. Další informace o vynucování vícefaktorového ověřování, když uživatel požádá o prostředek, který vyžaduje vícefaktorové ověřování, najdete v části Ochrana problému GitHubu s vícefaktorovým ověřováním.

Schéma ověřování je pojmenováno při konfiguraci ověřovací služby během ověřování. Příklad:

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();

V předchozím kódu byly přidány dva obslužné rutiny ověřování: jeden pro s a jeden pro cookienosný.

Poznámka

Zadáním výchozího schématu HttpContext.User se vlastnost nastaví na danou identitu. Pokud toto chování není žádoucí, zakažte ho vyvoláním bezparametrové AddAuthenticationformy .

Výběr schématu pomocí atributu Authorize

V okamžiku autorizace aplikace označuje obslužnou rutinu, která se má použít. Vyberte obslužnou rutinu, se kterou aplikace autorizuje předáním seznamu schémat ověřování oddělených čárkami .[Authorize] Atribut [Authorize] určuje schéma ověřování nebo schémata, která se mají použít bez ohledu na to, jestli je nakonfigurované výchozí nastavení. Příklad:

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());

}

V předchozím příkladu se cookie obslužné rutiny i obslužné rutiny nosné rutiny spouštějí a mají šanci vytvořit a připojit identitu pro aktuálního uživatele. Zadáním pouze jednoho schématu se spustí odpovídající obslužná rutina:

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

V předchozím kódu se spustí pouze obslužná rutina se schématem Bearer. Všechny cookieidentity založené na identitách se ignorují.

Výběr schématu pomocí zásad

Pokud dáváte přednost určení požadovaných schémat v zásadách, můžete kolekci nastavit AuthenticationSchemes při přidávání zásad:

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();

V předchozím příkladu se zásada Over18 spouští pouze proti identitě vytvořené obslužnou rutinou Bearer. Zásadu použijte nastavením vlastnosti atributu [Authorize]Policy :

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

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

Použití více schémat ověřování

Některé aplikace můžou potřebovat podporu více typů ověřování. Vaše aplikace může například ověřovat uživatele z Azure Active Directory a z databáze uživatelů. Dalším příkladem je aplikace, která ověřuje uživatele z Active Directory Federation Services (AD FS) i Azure Active Directory B2C. V tomto případě by aplikace měla přijmout nosný token JWT od několika vystavitelů.

Přidejte všechna schémata ověřování, která chcete přijmout. Následující kód například přidá dvě schémata ověřování nosných objektů JWT s různými vystavitely:

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();

Poznámka

Ve výchozím schématu JwtBearerDefaults.AuthenticationSchemeověřování je registrováno pouze jedno ověřování nosným uživatelem JWT . Další ověřování musí být registrováno pomocí jedinečného schématu ověřování.

Aktualizujte výchozí zásady autorizace tak, aby přijímaly obě schémata ověřování. Příklad:

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();

Vzhledem k tomu, že se přepíše výchozí zásady autorizace, je možné použít [Authorize] atribut v kontroleru. Kontroler pak přijme požadavky s JWT vydaným prvním nebo druhým vystavitelem.

Podívejte se na tento problém s GitHubem při používání více schémat ověřování.

Následující příklad používá Azure Active Directory B2C a dalšího tenanta Azure Active Directory :

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();

V předchozím kódu se používá k výběru výchozího schématu pro aktuální požadavek, ForwardDefaultSelector aby obslužné rutiny ověřování měly ve výchozím nastavení předávat všechny ověřovací operace. Výchozí logika předávání nejprve zkontroluje nejvýraznější ForwardAuthenticate, ForwardForbidForwardChallenge, , ForwardSignIna ForwardSignOut nastavení, následované kontrolou ForwardDefaultSelector, následované ForwardDefault. První výsledek, který není null, se používá jako cílové schéma pro předávání. Další informace najdete v tématu Schémata zásad v ASP.NET Core.

Úvod do schémat ověřování v ASP.NET Core najdete v tématu Schéma ověřování.

V některých scénářích, jako jsou jednostráňové aplikace (SPA), je běžné používat více metod ověřování. Aplikace může například použít cookieověřování na základě přihlašovacích údajů a ověřování nosných certifikátů JWT pro požadavky JavaScriptu. V některých případech může mít aplikace více instancí obslužné rutiny ověřování. Například dva cookie obslužné rutiny, kde jeden obsahuje základní identitu a jeden se vytvoří při aktivaci vícefaktorového ověřování (MFA). Vícefaktorové ověřování se může aktivovat, protože uživatel požádal o operaci, která vyžaduje dodatečné zabezpečení. Další informace o vynucování vícefaktorového ověřování, když uživatel požádá o prostředek, který vyžaduje vícefaktorové ověřování, najdete v části Ochrana problému GitHubu s vícefaktorovým ověřováním.

Schéma ověřování je pojmenováno při konfiguraci ověřovací služby během ověřování. Příklad:

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/";
        });

V předchozím kódu byly přidány dva obslužné rutiny ověřování: jeden pro s a jeden pro cookienosný.

Poznámka

Zadáním výchozího schématu HttpContext.User se vlastnost nastaví na danou identitu. Pokud toto chování není žádoucí, zakažte ho vyvoláním bezparametrové AddAuthenticationformy .

Výběr schématu pomocí atributu Authorize

V okamžiku autorizace aplikace označuje obslužnou rutinu, která se má použít. Vyberte obslužnou rutinu, se kterou aplikace autorizuje předáním seznamu schémat ověřování oddělených čárkami .[Authorize] Atribut [Authorize] určuje schéma ověřování nebo schémata, která se mají použít bez ohledu na to, jestli je nakonfigurované výchozí nastavení. Příklad:

[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;

V předchozím příkladu se cookie obslužné rutiny i obslužné rutiny nosné rutiny spouštějí a mají šanci vytvořit a připojit identitu pro aktuálního uživatele. Zadáním pouze jednoho schématu se spustí odpovídající obslužná rutina.

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

V předchozím kódu se spustí pouze obslužná rutina se schématem Bearer. Všechny cookieidentity založené na identitách se ignorují.

Výběr schématu pomocí zásad

Pokud dáváte přednost určení požadovaných schémat v zásadách, můžete kolekci nastavit AuthenticationSchemes při přidávání zásad:

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

V předchozím příkladu se zásada Over18 spouští pouze proti identitě vytvořené obslužnou rutinou Bearer. Zásadu použijte nastavením vlastnosti atributu [Authorize]Policy :

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

Použití více schémat ověřování

Některé aplikace můžou potřebovat podporu více typů ověřování. Vaše aplikace může například ověřovat uživatele z Azure Active Directory a z databáze uživatelů. Dalším příkladem je aplikace, která ověřuje uživatele z Active Directory Federation Services (AD FS) i Azure Active Directory B2C. V tomto případě by aplikace měla přijmout nosný token JWT od několika vystavitelů.

Přidejte všechna schémata ověřování, která chcete přijmout. Následující kód například Startup.ConfigureServices přidá dvě schémata ověřování nosných objektů JWT s různými vystavitely:

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/";
        });
}

Poznámka

Ve výchozím schématu JwtBearerDefaults.AuthenticationSchemeověřování je registrováno pouze jedno ověřování nosným uživatelem JWT . Další ověřování musí být registrováno pomocí jedinečného schématu ověřování.

Dalším krokem je aktualizace výchozích zásad autorizace tak, aby přijímala obě schémata ověřování. Příklad:

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();
    });
}

Vzhledem k tomu, že se přepíše výchozí zásady autorizace, je možné použít [Authorize] atribut v kontroleru. Kontroler pak přijme požadavky s JWT vydaným prvním nebo druhým vystavitelem.

Podívejte se na tento problém s GitHubem při používání více schémat ověřování.