Migrowanie uwierzytelniania i Identity do ASP.NET Core 2.0
Autor: Scott Addie i Hao Kung
ASP.NET Core 2.0 ma nowy model uwierzytelniania i Identity upraszcza konfigurację przy użyciu usług. ASP.NET aplikacje core 1.x korzystające z uwierzytelniania lub Identity można je zaktualizować, aby korzystać z nowego modelu, jak opisano poniżej.
Aktualizowanie przestrzeni nazw
W wersji 1.x klasy takie IdentityRole
i IdentityUser
zostały znalezione w Microsoft.AspNetCore.Identity.EntityFrameworkCore
przestrzeni nazw.
W wersji 2.0 Microsoft.AspNetCore.Identity przestrzeń nazw stała się nową home przestrzenią nazw dla kilku takich klas. W przypadku domyślnego Identity kodu klasy, których dotyczy problem, obejmują ApplicationUser
i Startup
. Dostosuj instrukcje using
, aby rozwiązać problemy z odwołaniami, których dotyczy problem.
Oprogramowanie pośredniczące uwierzytelniania i usługi
W projektach 1.x uwierzytelnianie jest konfigurowane za pośrednictwem oprogramowania pośredniczącego. Metoda oprogramowania pośredniczącego jest wywoływana dla każdego schematu uwierzytelniania, który chcesz obsługiwać.
Poniższy przykład w wersji 1.x umożliwia skonfigurowanie uwierzytelniania serwisu Facebook za pomocą Identity polecenia w programie :Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory)
{
app.UseIdentity();
app.UseFacebookAuthentication(new FacebookOptions {
AppId = Configuration["auth:facebook:appid"],
AppSecret = Configuration["auth:facebook:appsecret"]
});
}
W projektach 2.0 uwierzytelnianie jest konfigurowane za pośrednictwem usług. Każdy schemat uwierzytelniania jest zarejestrowany w ConfigureServices
metodzie Startup.cs
. Metoda UseIdentity
jest zastępowana ciągiem UseAuthentication
.
Poniższy przykład 2.0 umożliwia skonfigurowanie uwierzytelniania w usłudze Facebook za pomocą Identity polecenia w programie :Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
// If you want to tweak Identity cookies, they're no longer part of IdentityOptions.
services.ConfigureApplicationCookie(options => options.LoginPath = "/Account/LogIn");
services.AddAuthentication()
.AddFacebook(options =>
{
options.AppId = Configuration["auth:facebook:appid"];
options.AppSecret = Configuration["auth:facebook:appsecret"];
});
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) {
app.UseAuthentication();
}
Metoda UseAuthentication
dodaje pojedynczy składnik oprogramowania pośredniczącego uwierzytelniania, który jest odpowiedzialny za automatyczne uwierzytelnianie i obsługę żądań uwierzytelniania zdalnego. Zastępuje on wszystkie poszczególne składniki oprogramowania pośredniczącego jednym, typowym składnikiem oprogramowania pośredniczącego.
Poniżej przedstawiono instrukcje migracji 2.0 dla każdego głównego schematu uwierzytelniania.
CookieUwierzytelnianie oparte na protokole
Wybierz jedną z dwóch poniższych opcji i wprowadź niezbędne zmiany w pliku Startup.cs
:
Używanie plików cookie z Identity
Zastąp
UseIdentity
ciąg ciągiemUseAuthentication
w metodzieConfigure
:app.UseAuthentication();
Wywołaj metodę
AddIdentity
w metodzieConfigureServices
, aby dodać cookie usługi uwierzytelniania.Opcjonalnie wywołaj metodę
ConfigureApplicationCookie
orConfigureExternalCookie
w metodzieConfigureServices
, aby dostosować Identitycookie ustawienia.services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); services.ConfigureApplicationCookie(options => options.LoginPath = "/Account/LogIn");
Używanie plików cookie bez Identity
Zastąp
UseCookieAuthentication
wywołanie metody w metodzieConfigure
ciągiemUseAuthentication
:app.UseAuthentication();
Wywołaj
AddAuthentication
metody i w metodzieConfigureServices
:AddCookie
// If you don't want the cookie to be automatically authenticated and assigned to HttpContext.User, // remove the CookieAuthenticationDefaults.AuthenticationScheme parameter passed to AddAuthentication. services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/Account/LogIn"; options.LogoutPath = "/Account/LogOff"; });
Uwierzytelnianie elementu nośnego JWT
Wprowadź następujące zmiany w pliku Startup.cs
:
Zastąp
UseJwtBearerAuthentication
wywołanie metody w metodzieConfigure
ciągiemUseAuthentication
:app.UseAuthentication();
Wywołaj metodę
AddJwtBearer
w metodzieConfigureServices
:services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Audience = "http://localhost:5001/"; options.Authority = "http://localhost:5000/"; });
Ten fragment kodu nie używa Identityelementu , więc schemat domyślny powinien zostać ustawiony przez przekazanie
JwtBearerDefaults.AuthenticationScheme
doAddAuthentication
metody .
Uwierzytelnianie openID Connect (OIDC)
Wprowadź następujące zmiany w pliku Startup.cs
:
Zastąp
UseOpenIdConnectAuthentication
wywołanie metody w metodzieConfigure
ciągiemUseAuthentication
:app.UseAuthentication();
Wywołaj metodę
AddOpenIdConnect
w metodzieConfigureServices
:services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie() .AddOpenIdConnect(options => { options.Authority = Configuration["auth:oidc:authority"]; options.ClientId = Configuration["auth:oidc:clientid"]; });
Zastąp
PostLogoutRedirectUri
właściwość wOpenIdConnectOptions
akcji ciągiemSignedOutRedirectUri
:.AddOpenIdConnect(options => { options.SignedOutRedirectUri = "https://contoso.com"; });
Uwierzytelnianie za pomocą konta Facebook
Wprowadź następujące zmiany w pliku Startup.cs
:
Zastąp
UseFacebookAuthentication
wywołanie metody w metodzieConfigure
ciągiemUseAuthentication
:app.UseAuthentication();
Wywołaj metodę
AddFacebook
w metodzieConfigureServices
:services.AddAuthentication() .AddFacebook(options => { options.AppId = Configuration["auth:facebook:appid"]; options.AppSecret = Configuration["auth:facebook:appsecret"]; });
Uwierzytelnianie za pomocą konta Google
Wprowadź następujące zmiany w pliku Startup.cs
:
Zastąp
UseGoogleAuthentication
wywołanie metody w metodzieConfigure
ciągiemUseAuthentication
:app.UseAuthentication();
Wywołaj metodę
AddGoogle
w metodzieConfigureServices
:services.AddAuthentication() .AddGoogle(options => { options.ClientId = Configuration["auth:google:clientid"]; options.ClientSecret = Configuration["auth:google:clientsecret"]; });
Uwierzytelnianie za pomocą konta Microsoft
Aby uzyskać więcej informacji na temat uwierzytelniania konta Microsoft, zobacz ten problem z usługą GitHub.
Wprowadź następujące zmiany w pliku Startup.cs
:
Zastąp
UseMicrosoftAccountAuthentication
wywołanie metody w metodzieConfigure
ciągiemUseAuthentication
:app.UseAuthentication();
Wywołaj metodę
AddMicrosoftAccount
w metodzieConfigureServices
:services.AddAuthentication() .AddMicrosoftAccount(options => { options.ClientId = Configuration["auth:microsoft:clientid"]; options.ClientSecret = Configuration["auth:microsoft:clientsecret"]; });
Uwierzytelnianie za pomocą konta Twitter
Wprowadź następujące zmiany w pliku Startup.cs
:
Zastąp
UseTwitterAuthentication
wywołanie metody w metodzieConfigure
ciągiemUseAuthentication
:app.UseAuthentication();
Wywołaj metodę
AddTwitter
w metodzieConfigureServices
:services.AddAuthentication() .AddTwitter(options => { options.ConsumerKey = Configuration["auth:twitter:consumerkey"]; options.ConsumerSecret = Configuration["auth:twitter:consumersecret"]; });
Ustawianie domyślnych schematów uwierzytelniania
W wersji 1.x AutomaticAuthenticate
właściwości i AutomaticChallenge
klasy bazowej AuthenticationOptions miały zostać ustawione w jednym schemacie uwierzytelniania. Nie było dobrego sposobu, aby to wymusić.
W wersji 2.0 te dwie właściwości zostały usunięte jako właściwości w pojedynczym AuthenticationOptions
wystąpieniu. Można je skonfigurować w wywołaniu AddAuthentication
metody w ConfigureServices
metodzie w metodzie Startup.cs
:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);
W poprzednim fragmencie kodu domyślny schemat jest ustawiony na CookieAuthenticationDefaults.AuthenticationScheme
("Pliki cookie").
Alternatywnie użyj przeciążonej AddAuthentication
wersji metody, aby ustawić więcej niż jedną właściwość. W poniższym przykładzie przeciążonej metody domyślny schemat jest ustawiony na CookieAuthenticationDefaults.AuthenticationScheme
. Schemat uwierzytelniania można również określić w ramach poszczególnych [Authorize]
atrybutów lub zasad autoryzacji.
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
});
Zdefiniuj schemat domyślny w wersji 2.0, jeśli spełniony jest jeden z następujących warunków:
- Chcesz, aby użytkownik był automatycznie zalogowany
- Używasz atrybutu
[Authorize]
lub zasad autoryzacji bez określania schematów
Wyjątkiem od tej reguły jest AddIdentity
metoda . Ta metoda dodaje pliki cookie i ustawia domyślne schematy uwierzytelniania i wyzwania dla aplikacji cookieIdentityConstants.ApplicationScheme
. Ponadto ustawia domyślny schemat logowania na zewnętrzny cookieIdentityConstants.ExternalScheme
.
Używanie rozszerzeń uwierzytelniania HttpContext
Interfejs IAuthenticationManager
jest głównym punktem wejścia do systemu uwierzytelniania 1.x. Został zastąpiony nowym zestawem HttpContext
metod rozszerzeń w Microsoft.AspNetCore.Authentication
przestrzeni nazw.
Na przykład projekty 1.x odwołują się do Authentication
właściwości:
// Clear the existing external cookie to ensure a clean login process
await HttpContext.Authentication.SignOutAsync(_externalCookieScheme);
W projektach 2.0 zaimportuj Microsoft.AspNetCore.Authentication
Authentication
przestrzeń nazw i usuń odwołania do właściwości:
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
Uwierzytelnianie systemu Windows (HTTP.sys/ IISIntegration)
Istnieją dwie odmiany uwierzytelniania systemu Windows:
Host zezwala tylko na uwierzytelnionych użytkowników. Ta odmiana nie ma wpływu na zmiany w wersji 2.0.
Host zezwala zarówno na użytkowników anonimowych, jak i uwierzytelnionych. Ta odmiana ma wpływ na zmiany w wersji 2.0. Na przykład aplikacja powinna zezwalać anonimowym użytkownikom na warstwie usług IIS lub HTTP.sys , ale autoryzować użytkowników na poziomie kontrolera. W tym scenariuszu ustaw schemat domyślny w metodzie
Startup.ConfigureServices
.W przypadku wartości Microsoft.AspNetCore.Server.IISIntegration ustaw schemat domyślny na
IISDefaults.AuthenticationScheme
:using Microsoft.AspNetCore.Server.IISIntegration; services.AddAuthentication(IISDefaults.AuthenticationScheme);
W przypadku elementu Microsoft.AspNetCore.Server.HttpSys ustaw schemat domyślny na
HttpSysDefaults.AuthenticationScheme
:using Microsoft.AspNetCore.Server.HttpSys; services.AddAuthentication(HttpSysDefaults.AuthenticationScheme);
Nie można ustawić schematu domyślnego uniemożliwia pracę żądania autoryzacji (wyzwanie) z następującym wyjątkiem:
System.InvalidOperationException
: nie określono parametru authenticationScheme i nie znaleziono elementu DefaultChallengeScheme.
Aby uzyskać więcej informacji, zobacz Konfigurowanie uwierzytelniania systemu Windows w ASP.NET Core.
Wystąpienia IdentityCookieOptions
Efektem ubocznym zmian w wersji 2.0 jest przejście na używanie nazwanych opcji zamiast cookie wystąpień opcji. Możliwość dostosowywania nazw schematów Identitycookie jest usuwana.
Na przykład projekty 1.x używają iniekcji konstruktora do przekazywania parametru IdentityCookieOptions
do AccountController.cs
i ManageController.cs
. Dostęp do schematu uwierzytelniania zewnętrznego cookie jest uzyskiwany z podanego wystąpienia:
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IOptions<IdentityCookieOptions> identityCookieOptions,
IEmailSender emailSender,
ISmsSender smsSender,
ILoggerFactory loggerFactory)
{
_userManager = userManager;
_signInManager = signInManager;
_externalCookieScheme = identityCookieOptions.Value.ExternalCookieAuthenticationScheme;
_emailSender = emailSender;
_smsSender = smsSender;
_logger = loggerFactory.CreateLogger<AccountController>();
}
Wyżej wymienione wstrzykiwanie konstruktora staje się niepotrzebne w projektach 2.0, a _externalCookieScheme
pole można usunąć:
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ISmsSender smsSender,
ILoggerFactory loggerFactory)
{
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
_smsSender = smsSender;
_logger = loggerFactory.CreateLogger<AccountController>();
}
Projekty 1.x używały _externalCookieScheme
pola w następujący sposób:
// Clear the existing external cookie to ensure a clean login process
await HttpContext.Authentication.SignOutAsync(_externalCookieScheme);
W projektach 2.0 zastąp powyższy kod poniższym kodem. Stała IdentityConstants.ExternalScheme
może być używana bezpośrednio.
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
Rozwiąż nowo dodane SignOutAsync
wywołanie, importując następującą przestrzeń nazw:
using Microsoft.AspNetCore.Authentication;
Dodawanie właściwości nawigacji poCO elementu IdentityUser
Właściwości nawigacji podstawowego IdentityUser
modelu POCO (Zwykły stary obiekt CLR) platformy Entity Framework (EF) zostały usunięte. Jeśli projekt 1.x używał tych właściwości, ręcznie dodaj je z powrotem do projektu 2.0:
/// <summary>
/// Navigation property for the roles this user belongs to.
/// </summary>
public virtual ICollection<IdentityUserRole<int>> Roles { get; } = new List<IdentityUserRole<int>>();
/// <summary>
/// Navigation property for the claims this user possesses.
/// </summary>
public virtual ICollection<IdentityUserClaim<int>> Claims { get; } = new List<IdentityUserClaim<int>>();
/// <summary>
/// Navigation property for this users login accounts.
/// </summary>
public virtual ICollection<IdentityUserLogin<int>> Logins { get; } = new List<IdentityUserLogin<int>>();
Aby zapobiec duplikowaniu kluczy obcych podczas uruchamiania EF Core funkcji Migrations, dodaj następujący kod do IdentityDbContext
metody klasy OnModelCreating
(po wywołaniu base.OnModelCreating();
):
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Core Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Core Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
builder.Entity<ApplicationUser>()
.HasMany(e => e.Claims)
.WithOne()
.HasForeignKey(e => e.UserId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<ApplicationUser>()
.HasMany(e => e.Logins)
.WithOne()
.HasForeignKey(e => e.UserId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<ApplicationUser>()
.HasMany(e => e.Roles)
.WithOne()
.HasForeignKey(e => e.UserId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
}
Zastąp element GetExternalAuthenticationSchemes
Metoda GetExternalAuthenticationSchemes
synchroniczna została usunięta na rzecz wersji asynchronicznej. Projekty 1.x mają następujący kod w pliku Controllers/ManageController.cs
:
var otherLogins = _signInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList();
Ta metoda jest również wyświetlana w Views/Account/Login.cshtml
pliku :
@{
var loginProviders = SignInManager.GetExternalAuthenticationSchemes().ToList();
if (loginProviders.Count == 0)
{
<div>
<p>
There are no external authentication services configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
for details on setting up this ASP.NET application to support logging in via external services.
</p>
</div>
}
else
{
<form asp-controller="Account" asp-action="ExternalLogin" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal">
<div>
<p>
@foreach (var provider in loginProviders)
{
<button type="submit" class="btn btn-default" name="provider" value="@provider.AuthenticationScheme" title="Log in using your @provider.DisplayName account">@provider.AuthenticationScheme</button>
}
</p>
</div>
</form>
}
}
W projektach 2.0 użyj GetExternalAuthenticationSchemesAsync metody . Zmiana w pliku ManageController.cs
przypomina następujący kod:
var schemes = await _signInManager.GetExternalAuthenticationSchemesAsync();
var otherLogins = schemes.Where(auth => userLogins.All(ul => auth.Name != ul.LoginProvider)).ToList();
W Login.cshtml
pliku AuthenticationScheme
właściwość dostępna w foreach
pętli zmienia się na Name
:
@{
var loginProviders = (await SignInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (loginProviders.Count == 0)
{
<div>
<p>
There are no external authentication services configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
for details on setting up this ASP.NET application to support logging in via external services.
</p>
</div>
}
else
{
<form asp-controller="Account" asp-action="ExternalLogin" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal">
<div>
<p>
@foreach (var provider in loginProviders)
{
<button type="submit" class="btn btn-default" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
}
</p>
</div>
</form>
}
}
Zmiana właściwości ManageLoginsViewModel
Obiekt ManageLoginsViewModel
jest używany w ManageLogins
akcji .ManageController.cs
W projektach 1.x zwracany OtherLogins
typ właściwości obiektu to IList<AuthenticationDescription>
. Ten typ zwracany wymaga zaimportowania elementu Microsoft.AspNetCore.Http.Authentication
:
using System.Collections.Generic;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Identity;
namespace AspNetCoreDotNetCore1App.Models.ManageViewModels
{
public class ManageLoginsViewModel
{
public IList<UserLoginInfo> CurrentLogins { get; set; }
public IList<AuthenticationDescription> OtherLogins { get; set; }
}
}
W projektach 2.0 zwracany typ zmienia się na IList<AuthenticationScheme>
. Ten nowy typ zwracany Microsoft.AspNetCore.Http.Authentication
wymaga zastąpienia importu importem Microsoft.AspNetCore.Authentication
.
using System.Collections.Generic;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
namespace AspNetCoreDotNetCore2App.Models.ManageViewModels
{
public class ManageLoginsViewModel
{
public IList<UserLoginInfo> CurrentLogins { get; set; }
public IList<AuthenticationScheme> OtherLogins { get; set; }
}
}
Dodatkowe zasoby
Aby uzyskać więcej informacji, zobacz temat Dyskusja dotycząca problemu z uwierzytelnianiem 2.0 w witrynie GitHub.