Поделиться через


Сопоставление, настройка и преобразование утверждений в ASP.NET Core

Дэмиен Боуден

Утверждения можно создавать из любых данных пользователя или данных удостоверения личности, которые могут быть созданы с помощью доверенного поставщика удостоверений или удостоверений ASP.NET Core. Утверждение — это пара «имя-значение», которая описывает, кем является субъект, а не то, что он может делать. В этой статье рассматриваются следующие области:

  • Настройка и сопоставление утверждений с помощью клиента OpenID Connect
  • Установите утверждение имени и роли
  • Сброс пространств имен утверждений
  • Настройка, расширение утверждений с помощью TransformAsync

Сопоставление утверждений с помощью проверки подлинности OpenID Connect

Утверждения профиля можно вернуть в id_tokenобъекте, который возвращается после успешной аутентификации. Для клиентского приложения ASP.NET Core требуется только область профиля. При использовании id_token для утверждений не требуется дополнительное сопоставление утверждений.

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       options.SignInScheme = "Cookies";
       options.Authority = "-your-identity-provider-";
       options.RequireHttpsMetadata = true;
       options.ClientId = "-your-clientid-";
       options.ClientSecret = "-your-client-secret-from-user-secrets-or-keyvault";
       options.ResponseType = "code";
       options.UsePkce = true;
       options.Scope.Add("profile");
       options.SaveTokens = true;
   });

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

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

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

app.MapRazorPages();

app.Run();

Для предыдущего кода требуется пакет NuGet Microsoft.AspNetCore.Authentication.OpenIdConnect .

Другим способом получения утверждений пользователя является использование API сведений о пользователе OpenID Connect. Клиентское приложение ASP.NET Core использует GetClaimsFromUserInfoEndpoint свойство для настройки этого свойства. Одним из важных отличий от первых параметров является то, что необходимо использовать метод MapUniqueJsonKey, чтобы указать требуемые утверждения, в противном случае в клиентском приложении будут доступны только стандартные утверждения name, given_name и email. Утверждения, включенные в список id_token , сопоставляются по умолчанию. Это основное отличие от первого варианта. Необходимо явно определить некоторые необходимые утверждения.

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       options.SignInScheme = "Cookies";
       options.Authority = "-your-identity-provider-";
       options.RequireHttpsMetadata = true;
       options.ClientId = "-your-clientid-";
       options.ClientSecret = "-client-secret-from-user-secrets-or-keyvault";
       options.ResponseType = "code";
       options.UsePkce = true;
       options.Scope.Add("profile");
       options.SaveTokens = true;
       options.GetClaimsFromUserInfoEndpoint = true;
       options.ClaimActions.MapUniqueJsonKey("preferred_username",
                                             "preferred_username");
       options.ClaimActions.MapUniqueJsonKey("gender", "gender");
   });

var app = builder.Build();

// Code removed for brevity.

Примечание.

По умолчанию обработчик Open ID Connect использует запросы авторизации по протоколу PAR, если документ обнаружения поставщика удостоверений заявляет о поддержке PAR. Документ обнаружения поставщика удостоверений обычно находится в .well-known/openid-configuration. Если невозможно использовать PAR в конфигурации клиента у поставщика удостоверений, можно отключить PAR, используя параметр PushedAuthorizationBehavior.

builder.Services
    .AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddCookie()
    .AddOpenIdConnect("oidc", oidcOptions =>
    {
        // Other provider-specific configuration goes here.

        // The default value is PushedAuthorizationBehavior.UseIfAvailable.

        // 'OpenIdConnectOptions' does not contain a definition for 'PushedAuthorizationBehavior'
        // and no accessible extension method 'PushedAuthorizationBehavior' accepting a first argument
        // of type 'OpenIdConnectOptions' could be found
        oidcOptions.PushedAuthorizationBehavior = PushedAuthorizationBehavior.Disable;
    });

Чтобы убедиться, что проверка подлинности выполняется только в том случае, если используется PAR, используйте вместо этого PushedAuthorizationBehavior.Require. Это изменение также представляет новое событие OnPushAuthorization для OpenIdConnectEvents, которое можно использовать для настройки запроса принудительной авторизации или обработки его вручную. Дополнительные сведения см. в предложении API .

Сопоставление заявлений об именах и ролях

Утверждения Name и Role сопоставляются со свойствами по умолчанию в контексте HTTP ASP.NET Core. Иногда требуется использовать различные утверждения для свойств по умолчанию, или утверждения имени и роли не совпадают со значениями по умолчанию. Утверждения можно сопоставить с помощью свойства TokenValidationParameters и задать любое утверждение по мере необходимости. Значения из утверждений можно использовать непосредственно в HttpContext User.Identity.Name и роли.

User.Identity.Name Если у User.Identity.Name нет значения или отсутствуют роли, проверьте значения в возвращённых требованиях и задайте значения для NameClaimType и RoleClaimType. Возвращенные утверждения из проверки подлинности клиента можно просмотреть в контексте HTTP.

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
  .AddCookie()
  .AddOpenIdConnect(options =>
  {
       // Other options...
       options.TokenValidationParameters = new TokenValidationParameters
       {
          NameClaimType = "email"
          //, RoleClaimType = "role"
       };
  });

Пространства имен утверждений, пространства имен по умолчанию

ASP.NET Core добавляет пространства имен по умолчанию в некоторые известные утверждения, которые могут не потребоваться в приложении. При необходимости отключите эти добавленные пространства имен и используйте точные утверждения, созданные сервером OpenID Connect.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

JsonWebTokenHandler.DefaultInboundClaimTypeMap.Clear();

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       options.SignInScheme = "Cookies";
       options.Authority = "-your-identity-provider-";
       options.RequireHttpsMetadata = true;
       options.ClientId = "-your-clientid-";
       options.ClientSecret = "-your-client-secret-from-user-secrets-or-keyvault";
       options.ResponseType = "code";
       options.UsePkce = true;
       options.Scope.Add("profile");
       options.SaveTokens = true;
   });

var app = builder.Build();

// Code removed for brevity.
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       options.SignInScheme = "Cookies";
       options.Authority = "-your-identity-provider-";
       options.RequireHttpsMetadata = true;
       options.ClientId = "-your-clientid-";
       options.ClientSecret = "-your-client-secret-from-user-secrets-or-keyvault";
       options.ResponseType = "code";
       options.UsePkce = true;
       options.Scope.Add("profile");
       options.SaveTokens = true;
   });

var app = builder.Build();

// Code removed for brevity.

Если необходимо отключить пространства имен для каждой схемы, а не глобально, можно использовать параметр MapInboundClaims = false .

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       options.SignInScheme = "Cookies";
       options.Authority = "-your-identity-provider-";
       options.RequireHttpsMetadata = true;
       options.ClientId = "-your-clientid-";
       options.ClientSecret = "-your-client-secret-from-user-secrets-or-keyvault";
       options.ResponseType = "code";
       options.UsePkce = true;
       options.MapInboundClaims = false;
       options.Scope.Add("profile");
       options.SaveTokens = true;
   });

var app = builder.Build();

// Code removed for brevity.

Расширение или добавление настраиваемых утверждений с помощью IClaimsTransformation

Интерфейс IClaimsTransformation можно использовать для добавления дополнительных утверждений в ClaimsPrincipal класс. Для интерфейса требуется один метод TransformAsync. Этот метод может вызываться несколько раз. Добавьте новое утверждение только в том случае, если оно еще не существует в ClaimsPrincipal. Создается ClaimsIdentity для добавления новых утверждений, и его можно добавить в ClaimsPrincipal.

using Microsoft.AspNetCore.Authentication;
using System.Security.Claims;

public class MyClaimsTransformation : IClaimsTransformation
{
    public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        ClaimsIdentity claimsIdentity = new ClaimsIdentity();
        var claimType = "myNewClaim";
        if (!principal.HasClaim(claim => claim.Type == claimType))
        {
            claimsIdentity.AddClaim(new Claim(claimType, "myClaimValue"));
        }

        principal.AddIdentity(claimsIdentity);
        return Task.FromResult(principal);
    }
}

Интерфейс IClaimsTransformation и MyClaimsTransformation класс можно зарегистрировать как службу:

builder.Services.AddTransient<IClaimsTransformation, MyClaimsTransformation>();

Сопоставление утверждений от внешних поставщиков удостоверений

См. следующий документ:

Сохранение дополнительных утверждений и маркеров от внешних поставщиков в ASP.NET Core

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

  • Настройка и сопоставление утверждений с помощью клиента OpenID Connect
  • Установите имя и утверждение роли
  • Сброс пространств имен утверждений
  • Настройка, расширение утверждений с помощью TransformAsync

Сопоставление утверждений с помощью проверки подлинности OpenID Connect

Утверждения профиля могут быть возвращены в id_token, который возвращается после успешной аутентификации. Клиентское приложение ASP.NET Core требует только области профиля. При использовании id_token для утверждений не требуется дополнительное сопоставление утверждений.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       options.SignInScheme = "Cookies";
       options.Authority = "-your-identity-provider-";
       options.RequireHttpsMetadata = true;
       options.ClientId = "-your-clientid-";
       options.ClientSecret = "-your-client-secret-from-user-secrets-or-keyvault";
       options.ResponseType = "code";
       options.UsePkce = true;
       options.Scope.Add("profile");
       options.SaveTokens = true;
   });

Другим способом получения утверждений пользователя является использование API сведений о пользователе OpenID Connect. Клиентское приложение ASP.NET Core использует GetClaimsFromUserInfoEndpoint свойство для настройки этого свойства. Одно из важных отличий от первых настроек заключается в том, что необходимо указать требуемые утверждения, используя метод MapUniqueJsonKey, в противном случае в клиентском приложении будут доступны только стандартные утверждения name, given_name и email. Требования, включенные в список id_token, сопоставляются по умолчанию. Это основное отличие от первого варианта. Необходимо явно определить некоторые необходимые утверждения.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       options.SignInScheme = "Cookies";
       options.Authority = "-your-identity-provider-";
       options.RequireHttpsMetadata = true;
       options.ClientId = "-your-clientid-";
       options.ClientSecret = "-your-client-secret-from-user-secrets-or-keyvault";
       options.ResponseType = "code";
       options.UsePkce = true;
       options.Scope.Add("profile");
       options.SaveTokens = true;
       options.GetClaimsFromUserInfoEndpoint = true;
       options.ClaimActions.MapUniqueJsonKey("preferred_username", "preferred_username");
       options.ClaimActions.MapUniqueJsonKey("gender", "gender");
   }); 

Сопоставление утверждений имен и ролей

Утверждения Name и Role сопоставляются со свойствами по умолчанию в контексте HTTP ASP.NET Core. Иногда требуется использовать различные утверждения для свойств по умолчанию или когда утверждение имени и утверждение роли не соответствуют значениям по умолчанию. Утверждения можно сопоставить с помощью свойства TokenValidationParameters и задать любое утверждение по мере необходимости. Значения из утверждений можно использовать непосредственно в свойстве User..Name HttpContext и ролях.

Если у User.Identity.Name нет значения или отсутствуют роли, проверьте значения в возвращенных утверждениях и укажите значения для NameClaimType и RoleClaimType. Возвращенные утверждения из проверки подлинности клиента можно просмотреть в контексте HTTP.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
   .AddCookie()
   .AddOpenIdConnect(options =>
   {
       // other options...
       options.TokenValidationParameters = new TokenValidationParameters
       {
         NameClaimType = "email", 
         // RoleClaimType = "role"
       };
   });

Пространства имен утверждений, пространства имен по умолчанию

ASP.NET Core добавляет пространства имен по умолчанию в некоторые известные утверждения, которые могут не потребоваться в приложении. При необходимости отключите эти добавленные пространства имен и используйте точные утверждения, созданные сервером OpenID Connect.

public void Configure(IApplicationBuilder app)
{
    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

Расширение или добавление настраиваемых утверждений с помощью IClaimsTransformation

Интерфейс IClaimsTransformation можно использовать для добавления дополнительных утверждений в ClaimsPrincipal класс. Для интерфейса требуется один метод TransformAsync. Этот метод может вызываться несколько раз. Добавьте новое утверждение только если оно еще не существует в ClaimsPrincipal. Создается ClaimsIdentity для добавления новых требований, и его можно добавить в ClaimsPrincipal.

public class MyClaimsTransformation : IClaimsTransformation
{
    public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
       ClaimsIdentity claimsIdentity = new ClaimsIdentity();
       var claimType = "myNewClaim";
       if (!principal.HasClaim(claim => claim.Type == claimType))
       {		   
          claimsIdentity.AddClaim(new Claim(claimType, "myClaimValue"));
       }

       principal.AddIdentity(claimsIdentity);
       return Task.FromResult(principal);
    }
}

Интерфейс IClaimsTransformation и MyClaimsTransformation класс можно добавить в метод ConfigureServices в качестве службы.

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IClaimsTransformation, MyClaimsTransformation>();

Расширение или добавление пользовательских утверждений в ASP.NET Core Identity

См. следующий документ:

Добавление утверждений в Identity с использованием IUserClaimsPrincipalFactory

Сопоставление утверждений от внешних поставщиков удостоверений

См. следующий документ:

Сохранение дополнительных утверждений и маркеров от внешних поставщиков в ASP.NET Core