Авторизация с помощью определенной схемы в ASP.NET Core

Общие сведения о схемах проверки подлинности в ASP.NET Core см . в схеме проверки подлинности.

В некоторых сценариях, таких как одностраничные приложения (SPAs), обычно используются несколько методов проверки подлинности. Например, приложение может использовать cookieпроверку подлинности на основе на основе проверки подлинности для входа и проверки подлинности носителя JWT для запросов JavaScript. В некоторых случаях приложение может иметь несколько экземпляров обработчика проверки подлинности. Например, два cookie обработчика, в которых один содержит базовое удостоверение и создается при активации многофакторной проверки подлинности (MFA). MFA может быть активирован, так как пользователь запрашивал операцию, требующую дополнительной безопасности. Дополнительные сведения о применении MFA при запросе пользователем ресурса, требующего многофакторной проверки подлинности, см. в разделе " Защита проблемы GitHub" с MFA.

Схема проверки подлинности называется при настройке службы проверки подлинности во время проверки подлинности. Например:

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

В предыдущем коде добавлены два обработчика проверки подлинности: один для cookies и один для носителя.

Примечание.

Указание схемы по умолчанию приводит к HttpContext.User настройке свойства для этого удостоверения. Если это поведение не нужно, отключите его, вызвав параметрную форму AddAuthenticationбез параметров.

Выбор схемы с помощью атрибута "Авторизовать"

В точке авторизации приложение указывает, что обработчик будет использоваться. Выберите обработчик, с помощью которого приложение будет авторизовать, передав список схем проверки подлинности с разделителями-запятыми [Authorize]. Атрибут [Authorize] указывает схему проверки подлинности или схемы, которые следует использовать независимо от того, настроен ли по умолчанию. Например:

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

}

В предыдущем примере cookie обработчики носителя выполняются и имеют возможность создавать и добавлять удостоверение для текущего пользователя. Указав только одну схему, соответствующий обработчик выполняется:

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

В предыдущем коде запускается только обработчик со схемой носителя. Все cookieудостоверения на основе игнорируются.

Выбор схемы с политиками

Если вы предпочитаете указать нужные схемы в политике, можно задать коллекцию AuthenticationSchemes при добавлении политики:

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

В предыдущем примере политика "Over18" выполняется только для удостоверения, созданного обработчиком носителя. Используйте политику, задав [Authorize] свойство атрибута Policy :

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

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

Использование нескольких схем проверки подлинности

Некоторым приложениям может потребоваться поддержка нескольких типов проверки подлинности. Например, приложение может пройти проверку подлинности пользователей из Azure Active Directory и из базы данных пользователей. Другим примером является приложение, которое проверяет подлинность пользователей как из службы федерации Active Directory (AD FS), так и Azure Active Directory B2C. В этом случае приложение должно принять маркер носителя JWT из нескольких издателей.

Добавьте все схемы проверки подлинности, которые вы хотите принять. Например, следующий код добавляет две схемы проверки подлинности носителя JWT с различными издателями:

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

Примечание.

В схеме JwtBearerDefaults.AuthenticationSchemeпроверки подлинности по умолчанию регистрируется только одна проверка подлинности носителя JWT. Дополнительная проверка подлинности должна быть зарегистрирована с помощью уникальной схемы проверки подлинности.

Обновите политику авторизации по умолчанию, чтобы принять обе схемы проверки подлинности. Например:

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

По мере переопределения политики авторизации по умолчанию можно использовать [Authorize] атрибут в контроллерах. Затем контроллер принимает запросы с JWT, выданными первым или вторым издателем.

См . эту проблему GitHub по использованию нескольких схем проверки подлинности.

В следующем примере используется Azure Active Directory B2C и другой клиент 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();

В приведенном выше коде используется для выбора схемы по умолчанию для текущего запроса, ForwardDefaultSelector в который обработчики проверки подлинности должны пересылать все операции проверки подлинности по умолчанию. Логика пересылки по умолчанию проверка наиболее конкретных ForwardAuthenticate, ForwardForbidForwardChallengeи ForwardSignInForwardSignOut задает сначала, а затем проверка, за ForwardDefaultSelectorкоторым следует, а затем ForwardDefault. Первый результат, отличный от NULL, используется в качестве целевой схемы для перенаправления. Дополнительные сведения см. в схемах политики в ASP.NET Core.

Общие сведения о схемах проверки подлинности в ASP.NET Core см . в схеме проверки подлинности.

В некоторых сценариях, таких как одностраничные приложения (SPAs), обычно используются несколько методов проверки подлинности. Например, приложение может использовать cookieпроверку подлинности на основе на основе проверки подлинности для входа и проверки подлинности носителя JWT для запросов JavaScript. В некоторых случаях приложение может иметь несколько экземпляров обработчика проверки подлинности. Например, два cookie обработчика, в которых один содержит базовое удостоверение и создается при активации многофакторной проверки подлинности (MFA). MFA может быть активирован, так как пользователь запрашивал операцию, требующую дополнительной безопасности. Дополнительные сведения о применении MFA при запросе пользователем ресурса, требующего многофакторной проверки подлинности, см. в разделе " Защита проблемы GitHub" с MFA.

Схема проверки подлинности называется при настройке службы проверки подлинности во время проверки подлинности. Например:

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

В предыдущем коде добавлены два обработчика проверки подлинности: один для cookies и один для носителя.

Примечание.

Указание схемы по умолчанию приводит к HttpContext.User настройке свойства для этого удостоверения. Если это поведение не нужно, отключите его, вызвав параметрную форму AddAuthenticationбез параметров.

Выбор схемы с помощью атрибута "Авторизовать"

В точке авторизации приложение указывает, что обработчик будет использоваться. Выберите обработчик, с помощью которого приложение будет авторизовать, передав список схем проверки подлинности с разделителями-запятыми [Authorize]. Атрибут [Authorize] указывает схему проверки подлинности или схемы, которые следует использовать независимо от того, настроен ли по умолчанию. Например:

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

В предыдущем примере cookie обработчики носителя выполняются и имеют возможность создавать и добавлять удостоверение для текущего пользователя. Указав только одну схему, соответствующий обработчик запускается.

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

В предыдущем коде запускается только обработчик со схемой носителя. Все cookieудостоверения на основе игнорируются.

Выбор схемы с политиками

Если вы предпочитаете указать нужные схемы в политике, можно задать коллекцию AuthenticationSchemes при добавлении политики:

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

В предыдущем примере политика "Over18" выполняется только для удостоверения, созданного обработчиком носителя. Используйте политику, задав [Authorize] свойство атрибута Policy :

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

Использование нескольких схем проверки подлинности

Некоторым приложениям может потребоваться поддержка нескольких типов проверки подлинности. Например, приложение может пройти проверку подлинности пользователей из Azure Active Directory и из базы данных пользователей. Другим примером является приложение, которое проверяет подлинность пользователей как из службы федерации Active Directory (AD FS), так и Azure Active Directory B2C. В этом случае приложение должно принять маркер носителя JWT из нескольких издателей.

Добавьте все схемы проверки подлинности, которые вы хотите принять. Например, следующий код добавляет Startup.ConfigureServices две схемы проверки подлинности носителя JWT с различными издателями:

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

Примечание.

В схеме JwtBearerDefaults.AuthenticationSchemeпроверки подлинности по умолчанию регистрируется только одна проверка подлинности носителя JWT. Дополнительная проверка подлинности должна быть зарегистрирована с помощью уникальной схемы проверки подлинности.

Следующим шагом является обновление политики авторизации по умолчанию, чтобы принять обе схемы проверки подлинности. Например:

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

По мере переопределения политики авторизации по умолчанию можно использовать [Authorize] атрибут в контроллерах. Затем контроллер принимает запросы с JWT, выданными первым или вторым издателем.

См . эту проблему GitHub по использованию нескольких схем проверки подлинности.