Autoryzacja przy użyciu określonego schematu na platformie ASP.NET Core
Aby zapoznać się z wprowadzeniem do schematów uwierzytelniania w programie ASP.NET Core, zobacz Schemat uwierzytelniania.
W niektórych scenariuszach, takich jak aplikacje jednostronicowe (SPA), często używa się wielu metod uwierzytelniania. Na przykład aplikacja może używać cookieuwierzytelniania opartego na logowaniu i uwierzytelnianiu elementu nośnego JWT dla żądań języka JavaScript. W niektórych przypadkach aplikacja może mieć wiele wystąpień programu obsługi uwierzytelniania. Na przykład dwa cookie programy obsługi, w których jeden zawiera podstawowy identity element i jest tworzony po wyzwoleniu uwierzytelniania wieloskładnikowego (MFA). Uwierzytelnianie wieloskładnikowe może zostać wyzwolone, ponieważ użytkownik zażądał operacji wymagającej dodatkowych zabezpieczeń. Aby uzyskać więcej informacji na temat wymuszania uwierzytelniania wieloskładnikowego, gdy użytkownik żąda zasobu wymagającego uwierzytelniania wieloskładnikowego, zobacz sekcję GitHub issue Protect with MFA (Ochrona problemów z usługą GitHub za pomocą uwierzytelniania wieloskładnikowego).
Schemat uwierzytelniania jest nazwany, gdy usługa uwierzytelniania jest skonfigurowana podczas uwierzytelniania. Na przykład:
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();
W poprzednim kodzie dodano dwa programy obsługi uwierzytelniania: jeden dla plików cookie i jeden dla elementu nośnego.
Uwaga
Określenie schematu domyślnego powoduje HttpContext.User
, że właściwość jest ustawiona na wartość identity. Jeśli to zachowanie nie jest pożądane, wyłącz je, wywołując bez parametrów AddAuthentication
postać .
Wybieranie schematu z atrybutem Authorize
W momencie autoryzacji aplikacja wskazuje procedurę obsługi do użycia. Wybierz procedurę obsługi, za pomocą której aplikacja będzie autoryzowana, przekazując rozdzielaną przecinkami listę schematów uwierzytelniania do elementu [Authorize]
. Atrybut [Authorize]
określa schemat uwierzytelniania lub schematy do użycia niezależnie od tego, czy jest skonfigurowany domyślny. Na przykład:
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());
}
W poprzednim przykładzie zarówno programy obsługi elementu nośnego, jak cookie i mają szansę utworzyć i dołączyć element identity dla bieżącego użytkownika. Określając tylko pojedynczy schemat, odpowiedni program obsługi jest uruchamiany:
[Authorize(AuthenticationSchemes=JwtBearerDefaults.AuthenticationScheme)]
public class Mixed2Controller : Controller
{
public ContentResult Index() => Content(MyWidgets.GetMyContent());
}
W poprzednim kodzie jest uruchamiany tylko program obsługi ze schematem "Bearer". Wszystkie cookietożsamości oparte na tożsamościach są ignorowane.
Wybieranie schematu z zasadami
Jeśli wolisz określić żądane schematy w zasadach, możesz ustawić AuthenticationSchemes kolekcję podczas dodawania zasad:
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();
W poprzednim przykładzie zasady "Over18" są uruchamiane tylko względem utworzonego identity przez program obsługi "Bearer". Użyj zasad, ustawiając właściwość atrybutu [Authorize]
Policy
:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace AuthScheme.Controllers;
[Authorize(Policy = "Over18")]
public class RegistrationController : Controller
{
// Do Registration
Używanie wielu schematów uwierzytelniania
Niektóre aplikacje mogą wymagać obsługi wielu typów uwierzytelniania. Na przykład aplikacja może uwierzytelniać użytkowników z usługi Azure Active Directory i z bazy danych użytkowników. Innym przykładem jest aplikacja, która uwierzytelnia użytkowników zarówno z usług Active Directory Federation Services, jak i z usługi Azure Active Directory B2C. W takim przypadku aplikacja powinna zaakceptować token elementu nośnego JWT od kilku wystawców.
Dodaj wszystkie schematy uwierzytelniania, które chcesz zaakceptować. Na przykład poniższy kod dodaje dwa schematy uwierzytelniania elementu nośnego JWT z różnymi wystawcami:
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();
Uwaga
Tylko jedno uwierzytelnianie elementu nośnego JWT jest rejestrowane przy użyciu domyślnego schematu JwtBearerDefaults.AuthenticationScheme
uwierzytelniania. Dodatkowe uwierzytelnianie musi zostać zarejestrowane przy użyciu unikatowego schematu uwierzytelniania.
Zaktualizuj domyślne zasady autoryzacji, aby akceptowały oba schematy uwierzytelniania. Na przykład:
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();
Ponieważ domyślne zasady autoryzacji są zastępowane, można użyć atrybutu [Authorize]
w kontrolerach. Następnie kontroler akceptuje żądania z JWT wystawione przez pierwszego lub drugiego wystawcę.
Zobacz ten problem z usługą GitHub dotyczący korzystania z wielu schematów uwierzytelniania.
W poniższym przykładzie użyto usługi Azure Active Directory B2C i innej dzierżawy usługi 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();
W poprzednim kodzie służy do wybierania schematu domyślnego dla bieżącego żądania, ForwardDefaultSelector do którego programy obsługi uwierzytelniania powinny domyślnie przekazywać wszystkie operacje uwierzytelniania. Domyślna logika przekazywania sprawdza najpierw najbardziej specyficzne ForwardAuthenticateustawienia , , ForwardChallengeForwardForbid, ForwardSignIni ForwardSignOut , a następnie sprawdzając ForwardDefaultSelector, a następnie ForwardDefault. Pierwszy wynik bez wartości null jest używany jako schemat docelowy do przekazania dalej. Aby uzyskać więcej informacji, zobacz Schematy zasad w programie ASP.NET Core.
Aby zapoznać się z wprowadzeniem do schematów uwierzytelniania w programie ASP.NET Core, zobacz Schemat uwierzytelniania.
W niektórych scenariuszach, takich jak aplikacje jednostronicowe (SPA), często używa się wielu metod uwierzytelniania. Na przykład aplikacja może używać cookieuwierzytelniania opartego na logowaniu i uwierzytelnianiu elementu nośnego JWT dla żądań języka JavaScript. W niektórych przypadkach aplikacja może mieć wiele wystąpień programu obsługi uwierzytelniania. Na przykład dwa cookie programy obsługi, w których jeden zawiera podstawowy identity element i jest tworzony po wyzwoleniu uwierzytelniania wieloskładnikowego (MFA). Uwierzytelnianie wieloskładnikowe może zostać wyzwolone, ponieważ użytkownik zażądał operacji wymagającej dodatkowych zabezpieczeń. Aby uzyskać więcej informacji na temat wymuszania uwierzytelniania wieloskładnikowego, gdy użytkownik żąda zasobu wymagającego uwierzytelniania wieloskładnikowego, zobacz sekcję GitHub issue Protect with MFA (Ochrona problemów z usługą GitHub za pomocą uwierzytelniania wieloskładnikowego).
Schemat uwierzytelniania jest nazwany, gdy usługa uwierzytelniania jest skonfigurowana podczas uwierzytelniania. Na przykład:
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/";
});
W poprzednim kodzie dodano dwa programy obsługi uwierzytelniania: jeden dla plików cookie i jeden dla elementu nośnego.
Uwaga
Określenie schematu domyślnego powoduje HttpContext.User
, że właściwość jest ustawiona na wartość identity. Jeśli to zachowanie nie jest pożądane, wyłącz je, wywołując bez parametrów AddAuthentication
postać .
Wybieranie schematu z atrybutem Authorize
W momencie autoryzacji aplikacja wskazuje procedurę obsługi do użycia. Wybierz procedurę obsługi, za pomocą której aplikacja będzie autoryzowana, przekazując rozdzielaną przecinkami listę schematów uwierzytelniania do elementu [Authorize]
. Atrybut [Authorize]
określa schemat uwierzytelniania lub schematy do użycia niezależnie od tego, czy jest skonfigurowany domyślny. Na przykład:
[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;
W poprzednim przykładzie zarówno programy obsługi elementu nośnego, jak cookie i mają szansę utworzyć i dołączyć element identity dla bieżącego użytkownika. Określając tylko pojedynczy schemat, odpowiedni program obsługi jest uruchamiany.
[Authorize(AuthenticationSchemes =
JwtBearerDefaults.AuthenticationScheme)]
public class MixedController : Controller
W poprzednim kodzie jest uruchamiany tylko program obsługi ze schematem "Bearer". Wszystkie cookietożsamości oparte na tożsamościach są ignorowane.
Wybieranie schematu z zasadami
Jeśli wolisz określić żądane schematy w zasadach, możesz ustawić kolekcję podczas dodawania AuthenticationSchemes
zasad:
services.AddAuthorization(options =>
{
options.AddPolicy("Over18", policy =>
{
policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
policy.RequireAuthenticatedUser();
policy.Requirements.Add(new MinimumAgeRequirement());
});
});
W poprzednim przykładzie zasady "Over18" są uruchamiane tylko względem utworzonego identity przez program obsługi "Bearer". Użyj zasad, ustawiając właściwość atrybutu [Authorize]
Policy
:
[Authorize(Policy = "Over18")]
public class RegistrationController : Controller
Używanie wielu schematów uwierzytelniania
Niektóre aplikacje mogą wymagać obsługi wielu typów uwierzytelniania. Na przykład aplikacja może uwierzytelniać użytkowników z usługi Azure Active Directory i z bazy danych użytkowników. Innym przykładem jest aplikacja, która uwierzytelnia użytkowników zarówno z usług Active Directory Federation Services, jak i z usługi Azure Active Directory B2C. W takim przypadku aplikacja powinna zaakceptować token elementu nośnego JWT od kilku wystawców.
Dodaj wszystkie schematy uwierzytelniania, które chcesz zaakceptować. Na przykład poniższy kod w pliku Startup.ConfigureServices
dodaje dwa schematy uwierzytelniania elementu nośnego JWT z różnymi wystawcami:
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/";
});
}
Uwaga
Tylko jedno uwierzytelnianie elementu nośnego JWT jest rejestrowane przy użyciu domyślnego schematu JwtBearerDefaults.AuthenticationScheme
uwierzytelniania. Dodatkowe uwierzytelnianie musi zostać zarejestrowane przy użyciu unikatowego schematu uwierzytelniania.
Następnym krokiem jest zaktualizowanie domyślnych zasad autoryzacji w celu akceptowania obu schematów uwierzytelniania. Na przykład:
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();
});
}
Ponieważ domyślne zasady autoryzacji są zastępowane, można użyć atrybutu [Authorize]
w kontrolerach. Następnie kontroler akceptuje żądania z JWT wystawione przez pierwszego lub drugiego wystawcę.
Zobacz ten problem z usługą GitHub dotyczący korzystania z wielu schematów uwierzytelniania.