Otorisasi dengan skema tertentu di ASP.NET Core

Untuk pengenalan skema autentikasi di ASP.NET Core, lihat Skema autentikasi.

Dalam beberapa skenario, seperti Aplikasi Halaman Tunggal (SPAs), biasanya menggunakan beberapa metode autentikasi. Misalnya, aplikasi dapat menggunakan cookieautentikasi berbasis untuk masuk dan autentikasi pembawa JWT untuk permintaan JavaScript. Dalam beberapa kasus, aplikasi mungkin memiliki beberapa instans handler autentikasi. Misalnya, dua cookie handler di mana satu berisi identitas dasar dan satu dibuat ketika autentikasi multifaktor (MFA) telah dipicu. MFA dapat dipicu karena pengguna meminta operasi yang memerlukan keamanan ekstra. Untuk informasi selengkapnya tentang memberlakukan MFA saat pengguna meminta sumber daya yang memerlukan MFA, lihat bagian Perlindungan masalah GitHub dengan MFA.

Skema autentikasi diberi nama saat layanan autentikasi dikonfigurasi selama autentikasi. Contohnya:

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

Dalam kode sebelumnya, dua handler autentikasi telah ditambahkan: satu untuk cookies dan satu untuk pembawa.

Catatan

Menentukan hasil skema default dalam properti yang diatur ke identitas tersebut HttpContext.User . Jika perilaku tersebut tidak diinginkan, nonaktifkan dengan memanggil bentuk parameterless dari AddAuthentication.

Memilih skema dengan atribut Otorisasi

Pada titik otorisasi, aplikasi menunjukkan handler yang akan digunakan. Pilih handler yang akan diotorisasi aplikasi dengan meneruskan daftar skema autentikasi yang dibatasi koma ke [Authorize]. Atribut [Authorize] menentukan skema atau skema autentikasi yang akan digunakan terlepas dari apakah default dikonfigurasi. Contohnya:

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

}

Dalam contoh sebelumnya, penangan cookie dan pembawa berjalan dan memiliki kesempatan untuk membuat dan menambahkan identitas untuk pengguna saat ini. Dengan menentukan satu skema saja, handler yang sesuai berjalan:

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

Dalam kode sebelumnya, hanya handler dengan skema "Pembawa" yang berjalan. Identitas berbasis apa pun cookiediabaikan.

Memilih skema dengan kebijakan

Jika Anda lebih suka menentukan skema yang diinginkan dalam kebijakan, Anda dapat mengatur AuthenticationSchemes koleksi saat menambahkan kebijakan:

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

Dalam contoh sebelumnya, kebijakan "Over18" hanya berjalan terhadap identitas yang dibuat oleh handler "Bearer". Gunakan kebijakan dengan mengatur [Authorize] properti atribut Policy :

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

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

Menggunakan beberapa skema autentikasi

Beberapa aplikasi mungkin perlu mendukung beberapa jenis autentikasi. Misalnya, aplikasi Anda mungkin mengautentikasi pengguna dari Azure Active Directory dan dari database pengguna. Contoh lain adalah aplikasi yang mengautentikasi pengguna dari Layanan Federasi Direktori Aktif dan Azure Active Directory B2C. Dalam hal ini, aplikasi harus menerima token pembawa JWT dari beberapa penerbit.

Tambahkan semua skema autentikasi yang ingin Anda terima. Misalnya, kode berikut menambahkan dua skema autentikasi pembawa JWT dengan penerbit yang berbeda:

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

Catatan

Hanya satu autentikasi pembawa JWT yang terdaftar dengan skema JwtBearerDefaults.AuthenticationSchemeautentikasi default . Autentikasi tambahan harus didaftarkan dengan skema autentikasi unik.

Perbarui kebijakan otorisasi default untuk menerima kedua skema autentikasi. Contohnya:

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

Karena kebijakan otorisasi default ditimpa, anda dapat menggunakan [Authorize] atribut di pengontrol. Pengontrol kemudian menerima permintaan dengan JWT yang dikeluarkan oleh penerbit pertama atau kedua.

Lihat masalah GitHub ini tentang menggunakan beberapa skema autentikasi.

Contoh berikut menggunakan Azure Active Directory B2C dan penyewa Azure Active Directory lainnya:

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

Dalam kode sebelumnya, ForwardDefaultSelector digunakan untuk memilih skema default untuk permintaan saat ini yang harus diteruskan oleh penangan autentikasi ke semua operasi autentikasi secara default. Logika penerusan default memeriksa pengaturan , , , , dan yang paling spesifik ForwardAuthenticateterlebih dahulu, diikuti dengan memeriksa ForwardDefaultSelector, diikuti oleh ForwardDefault.ForwardSignOutForwardSignInForwardForbidForwardChallenge Hasil non-null pertama digunakan sebagai skema target untuk diteruskan. Untuk informasi selengkapnya, lihat Skema kebijakan di ASP.NET Core.

Untuk pengenalan skema autentikasi di ASP.NET Core, lihat Skema autentikasi.

Dalam beberapa skenario, seperti Aplikasi Halaman Tunggal (SPAs), biasanya menggunakan beberapa metode autentikasi. Misalnya, aplikasi dapat menggunakan cookieautentikasi berbasis untuk masuk dan autentikasi pembawa JWT untuk permintaan JavaScript. Dalam beberapa kasus, aplikasi mungkin memiliki beberapa instans handler autentikasi. Misalnya, dua cookie handler di mana satu berisi identitas dasar dan satu dibuat ketika autentikasi multifaktor (MFA) telah dipicu. MFA dapat dipicu karena pengguna meminta operasi yang memerlukan keamanan ekstra. Untuk informasi selengkapnya tentang memberlakukan MFA saat pengguna meminta sumber daya yang memerlukan MFA, lihat bagian Perlindungan masalah GitHub dengan MFA.

Skema autentikasi diberi nama saat layanan autentikasi dikonfigurasi selama autentikasi. Contohnya:

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

Dalam kode sebelumnya, dua handler autentikasi telah ditambahkan: satu untuk cookies dan satu untuk pembawa.

Catatan

Menentukan hasil skema default dalam properti yang diatur ke identitas tersebut HttpContext.User . Jika perilaku tersebut tidak diinginkan, nonaktifkan dengan memanggil bentuk parameterless dari AddAuthentication.

Memilih skema dengan atribut Otorisasi

Pada titik otorisasi, aplikasi menunjukkan handler yang akan digunakan. Pilih handler yang akan diotorisasi aplikasi dengan meneruskan daftar skema autentikasi yang dibatasi koma ke [Authorize]. Atribut [Authorize] menentukan skema atau skema autentikasi yang akan digunakan terlepas dari apakah default dikonfigurasi. Contohnya:

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

Dalam contoh sebelumnya, penangan cookie dan pembawa berjalan dan memiliki kesempatan untuk membuat dan menambahkan identitas untuk pengguna saat ini. Dengan menentukan satu skema saja, handler yang sesuai berjalan.

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

Dalam kode sebelumnya, hanya handler dengan skema "Pembawa" yang berjalan. Identitas berbasis apa pun cookiediabaikan.

Memilih skema dengan kebijakan

Jika Anda lebih suka menentukan skema yang diinginkan dalam kebijakan, Anda dapat mengatur AuthenticationSchemes koleksi saat menambahkan kebijakan Anda:

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

Dalam contoh sebelumnya, kebijakan "Over18" hanya berjalan terhadap identitas yang dibuat oleh handler "Bearer". Gunakan kebijakan dengan mengatur [Authorize] properti atribut Policy :

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

Menggunakan beberapa skema autentikasi

Beberapa aplikasi mungkin perlu mendukung beberapa jenis autentikasi. Misalnya, aplikasi Anda mungkin mengautentikasi pengguna dari Azure Active Directory dan dari database pengguna. Contoh lain adalah aplikasi yang mengautentikasi pengguna dari Layanan Federasi Direktori Aktif dan Azure Active Directory B2C. Dalam hal ini, aplikasi harus menerima token pembawa JWT dari beberapa penerbit.

Tambahkan semua skema autentikasi yang ingin Anda terima. Misalnya, kode berikut dalam Startup.ConfigureServices menambahkan dua skema autentikasi pembawa JWT dengan penerbit yang berbeda:

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

Catatan

Hanya satu autentikasi pembawa JWT yang terdaftar dengan skema JwtBearerDefaults.AuthenticationSchemeautentikasi default . Autentikasi tambahan harus didaftarkan dengan skema autentikasi unik.

Langkah selanjutnya adalah memperbarui kebijakan otorisasi default untuk menerima kedua skema autentikasi. Contohnya:

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

Karena kebijakan otorisasi default ditimpa, anda dapat menggunakan [Authorize] atribut di pengontrol. Pengontrol kemudian menerima permintaan dengan JWT yang dikeluarkan oleh penerbit pertama atau kedua.

Lihat masalah GitHub ini tentang menggunakan beberapa skema autentikasi.