Dela via


Auktorisera med ett specifikt schema i ASP.NET Core

En introduktion till autentiseringsscheman i ASP.NET Core finns i autentiseringsschema.

I vissa scenarier, till exempel ensidesprogram (SPA) är det vanligt att använda flera autentiseringsmetoder. Appen kan till exempel använda cookie-baserad autentisering för att logga in och JWT-ägarautentisering för JavaScript-begäranden. I vissa fall kan appen ha flera instanser av en autentiseringshanterare. Till exempel två cookie-hanterare där en innehåller en grundläggande identitet och en skapas när en multifaktorautentisering (MFA) har utlösts. MFA kan utlösas eftersom användaren begärde en åtgärd som kräver extra säkerhet. Mer information om hur du framtvingar MFA när en användare begär en resurs som kräver MFA finns i avsnittet GitHub-problem Skydda med MFA.

Ett autentiseringsschema namnges när autentiseringstjänsten konfigureras under autentiseringen. Till exempel:

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

I föregående kod har två autentiseringshanterare lagts till: en för cookies och en för ägaren.

Not

Om du anger standardschemat resulterar det i att egenskapen HttpContext.User anges till den identiteten. Om det beteendet inte är önskvärt inaktiverar du det genom att anropa den parameterlösa formen av AddAuthentication.

Välja schemat med attributet Auktorisera

Vid tidpunkten för auktoriseringen anger appen vilken hanterare som ska användas. Välj den hanterare som appen ska auktorisera genom att skicka en kommaavgränsad lista över autentiseringsscheman till [Authorize]. Attributet [Authorize] anger det autentiseringsschema eller de scheman som ska användas oavsett om ett standardvärde har konfigurerats. Till exempel:

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

}

I föregående exempel kör både cookie- och bärarhanterare och har en chans att skapa och lägga till en identitet för den aktuella användaren. Genom att endast ange ett enda schema körs motsvarande hanterare:

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

I föregående kod körs endast hanteraren med "Bearer"-schemat. Alla cookie-baserade identiteter ignoreras.

Välja schemat med riktlinjer

Om du föredrar att specificera önskade scheman i policykan du ställa in AuthenticationSchemes kollektion när du lägger till en policy.

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

I föregående exempel körs policyn "Over18" endast mot den identitet som hanteraren "Bearer" har skapat. Använd principen genom att ange [Authorize] attributets egenskap Policy:

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

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

Använda flera autentiseringsscheman

Vissa appar kan behöva stöd för flera typer av autentisering. Din app kan till exempel autentisera användare från Azure Active Directory och från en användardatabas. Ett annat exempel är en app som autentiserar användare från både Active Directory Federation Services och Azure Active Directory B2C. I det här fallet bör appen acceptera en JWT-ägartoken från flera utfärdare.

Lägg till alla autentiseringsscheman som du vill godkänna. Följande kod lägger till exempel två JWT-ägarautentiseringsscheman med olika utfärdare:

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

Anteckning

Endast en JWT-ägarautentisering registreras med standardautentiseringsschemat JwtBearerDefaults.AuthenticationScheme. Ytterligare autentisering måste registreras med ett unikt autentiseringsschema.

Uppdatera standardauktoriseringsprincipen för att acceptera båda autentiseringsschemana. Till exempel:

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

Eftersom standardauktoriseringsprincipen är åsidosatt kan du använda attributet [Authorize] i kontrollanter. Kontrollanten accepterar sedan begäranden med JWT (JSON Web Tokens) som utfärdats av den första eller andra utfärdaren.

Se det här GitHub-problemet om att använda flera autentiseringsscheman.

I följande exempel används Azure Active Directory B2C och en annan Azure Active Directory tenant:

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

I föregående kod används ForwardDefaultSelector för att välja ett standardschema för den aktuella begäran om att autentiseringshanterare ska vidarebefordra alla autentiseringsåtgärder till som standard. Standardlogik för vidarebefordran kontrollerar den mest specifika inställningen ForwardAuthenticate, ForwardChallenge, ForwardForbid, ForwardSignInoch ForwardSignOut först, följt av ForwardDefaultSelectorföljt av ForwardDefault. Det första resultatet som inte är null används som målschema att vidarebefordra till. Mer information finns i Principscheman i ASP.NET Core.

En introduktion till autentiseringsscheman i ASP.NET Core finns i autentiseringsschema.

I vissa scenarier, till exempel ensidesprogram (SPA) är det vanligt att använda flera autentiseringsmetoder. Appen kan till exempel använda cookie-baserad autentisering för att logga in och JWT-ägarautentisering för JavaScript-begäranden. I vissa fall kan appen ha flera instanser av en autentiseringshanterare. Till exempel två cookie-hanterare där en innehåller en grundläggande identitet och en skapas när en multifaktorautentisering (MFA) har utlösts. MFA kan utlösas eftersom användaren begärde en åtgärd som kräver extra säkerhet. Mer information om hur du framtvingar MFA när en användare begär en resurs som kräver MFA finns i avsnittet GitHub-problem Skydda med MFA.

Ett autentiseringsschema namnges när autentiseringstjänsten konfigureras under autentiseringen. Till exempel:

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

I föregående kod har två autentiseringshanterare lagts till: en för cookies och en för ägaren.

Anteckning

Om du anger standardschemat resulterar det i att egenskapen HttpContext.User anges till den identiteten. Om det beteendet inte är önskvärt inaktiverar du det genom att anropa den parameterlösa formen av AddAuthentication.

Välja schemat med attributet Auktorisera

Vid tidpunkten för auktoriseringen anger appen vilken hanterare som ska användas. Välj den hanterare som appen ska auktorisera genom att skicka en kommaavgränsad lista över autentiseringsscheman till [Authorize]. Attributet [Authorize] anger det autentiseringsschema eller de scheman som ska användas oavsett om ett standardvärde har konfigurerats. Till exempel:

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

I det föregående exemplet körs både cookie- och bärarhanterare, och de har en chans att skapa och lägga till en identitet för den aktuella användaren. Genom att endast ange ett enda schema körs motsvarande hanterare.

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

I föregående kod körs endast hanteraren med "Bearer"-schemat. Alla cookie-baserade identiteter ignoreras.

Välja schemat med principer

Om du föredrar att ange önskade scheman i principkan du ange AuthenticationSchemes-samlingen när du lägger till din princip:

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

I föregående exempel tillämpas principen "Over18" endast på den identitet som skapats av hanteraren "Bearer". Använd principen genom att ange [Authorize] attributets egenskap Policy:

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

Använda flera autentiseringsscheman

Vissa appar kan behöva stöd för flera typer av autentisering. Din app kan till exempel autentisera användare från Azure Active Directory och från en användardatabas. Ett annat exempel är en app som autentiserar användare från både Active Directory Federation Services och Azure Active Directory B2C. I det här fallet bör appen acceptera en JWT-ägartoken från flera utfärdare.

Lägg till alla autentiseringsscheman som du vill godkänna. Följande kod i Startup.ConfigureServices lägger till två JWT-ägarautentiseringsscheman med olika utfärdare:

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

Anteckning

Endast en JWT-ägarautentisering registreras med standardautentiseringsschemat JwtBearerDefaults.AuthenticationScheme. Ytterligare autentisering måste registreras med ett unikt autentiseringsschema.

Nästa steg är att uppdatera standardauktoriseringsprincipen för att acceptera båda autentiseringsschemana. Till exempel:

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

Eftersom standardauktoriseringsprincipen är åsidosatt kan du använda attributet [Authorize] i kontrollanter. Styrenheten accepterar sedan förfrågningar med JWT utfärdade av den första eller andra utfärdaren.

Se det här GitHub-problemet om att använda flera autentiseringsscheman.