Eseguire la migrazione dell'autenticazione e Identity a ASP.NET Core 2.0
Di Scott Addie e Hao Kung
ASP.NET Core 2.0 ha un nuovo modello per l'autenticazione e Identity semplifica la configurazione usando i servizi. ASP.NET applicazioni Core 1.x che usano l'autenticazione o Identity possono essere aggiornate per usare il nuovo modello come descritto di seguito.
Aggiornare gli spazi dei nomi
Nella versione 1.x, le classi di questo IdentityRole
tipo e IdentityUser
sono state trovate nello spazio dei Microsoft.AspNetCore.Identity.EntityFrameworkCore
nomi .
Nella versione 2.0 lo Microsoft.AspNetCore.Identity spazio dei nomi è diventato il nuovo home per diverse di queste classi. Con il codice predefinito Identity , le classi interessate includono ApplicationUser
e Startup
. using
Modificare le istruzioni per risolvere i riferimenti interessati.
Middleware e servizi di autenticazione
Nei progetti 1.x l'autenticazione viene configurata tramite middleware. Viene richiamato un metodo middleware per ogni schema di autenticazione che si vuole supportare.
L'esempio 1.x seguente configura l'autenticazione di Facebook con Identity in 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"]
});
}
Nei progetti 2.0 l'autenticazione viene configurata tramite i servizi. Ogni schema di autenticazione viene registrato nel ConfigureServices
metodo di Startup.cs
. Il UseIdentity
metodo viene sostituito con UseAuthentication
.
L'esempio 2.0 seguente configura l'autenticazione di Facebook con Identity in 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();
}
Il UseAuthentication
metodo aggiunge un singolo componente middleware di autenticazione, responsabile dell'autenticazione automatica e della gestione delle richieste di autenticazione remota. Sostituisce tutti i singoli componenti middleware con un singolo componente middleware comune.
Di seguito sono riportate le istruzioni di migrazione 2.0 per ogni schema di autenticazione principale.
CookieAutenticazione basata su
Selezionare una delle due opzioni seguenti e apportare le modifiche necessarie in Startup.cs
:
Usare i cookie con Identity
Sostituire
UseIdentity
conUseAuthentication
nelConfigure
metodo :app.UseAuthentication();
Richiamare il
AddIdentity
metodo nelConfigureServices
metodo per aggiungere i cookie servizi di autenticazione.Facoltativamente, richiamare il
ConfigureApplicationCookie
metodo oConfigureExternalCookie
nelConfigureServices
metodo per modificare le Identitycookie impostazioni.services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); services.ConfigureApplicationCookie(options => options.LoginPath = "/Account/LogIn");
Usare i cookie senza Identity
Sostituire la chiamata al
UseCookieAuthentication
Configure
metodo nel metodo conUseAuthentication
:app.UseAuthentication();
Richiamare i
AddAuthentication
metodi eAddCookie
nelConfigureServices
metodo :// 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"; });
Autenticazione del bearer JWT
Modificare Startup.cs
nel modo seguente:
Sostituire la chiamata al
UseJwtBearerAuthentication
Configure
metodo nel metodo conUseAuthentication
:app.UseAuthentication();
Richiamare il
AddJwtBearer
metodo nelConfigureServices
metodo :services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Audience = "http://localhost:5001/"; options.Authority = "http://localhost:5000/"; });
Questo frammento di codice non usa Identity, quindi lo schema predefinito deve essere impostato passando
JwtBearerDefaults.AuthenticationScheme
alAddAuthentication
metodo .
Autenticazione OIDC (OpenID Connect)
Modificare Startup.cs
nel modo seguente:
Sostituire la chiamata al
UseOpenIdConnectAuthentication
Configure
metodo nel metodo conUseAuthentication
:app.UseAuthentication();
Richiamare il
AddOpenIdConnect
metodo nelConfigureServices
metodo :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"]; });
Sostituire la
PostLogoutRedirectUri
proprietà nell'azioneOpenIdConnectOptions
conSignedOutRedirectUri
:.AddOpenIdConnect(options => { options.SignedOutRedirectUri = "https://contoso.com"; });
Autenticazione di Facebook
Modificare Startup.cs
nel modo seguente:
Sostituire la chiamata al
UseFacebookAuthentication
Configure
metodo nel metodo conUseAuthentication
:app.UseAuthentication();
Richiamare il
AddFacebook
metodo nelConfigureServices
metodo :services.AddAuthentication() .AddFacebook(options => { options.AppId = Configuration["auth:facebook:appid"]; options.AppSecret = Configuration["auth:facebook:appsecret"]; });
Autenticazione di Google
Modificare Startup.cs
nel modo seguente:
Sostituire la chiamata al
UseGoogleAuthentication
Configure
metodo nel metodo conUseAuthentication
:app.UseAuthentication();
Richiamare il
AddGoogle
metodo nelConfigureServices
metodo :services.AddAuthentication() .AddGoogle(options => { options.ClientId = Configuration["auth:google:clientid"]; options.ClientSecret = Configuration["auth:google:clientsecret"]; });
Autenticazione di account Microsoft
Per altre informazioni sull'autenticazione dell'account Microsoft, vedere questo problema di GitHub.
Modificare Startup.cs
nel modo seguente:
Sostituire la chiamata al
UseMicrosoftAccountAuthentication
Configure
metodo nel metodo conUseAuthentication
:app.UseAuthentication();
Richiamare il
AddMicrosoftAccount
metodo nelConfigureServices
metodo :services.AddAuthentication() .AddMicrosoftAccount(options => { options.ClientId = Configuration["auth:microsoft:clientid"]; options.ClientSecret = Configuration["auth:microsoft:clientsecret"]; });
Autenticazione di Twitter
Modificare Startup.cs
nel modo seguente:
Sostituire la chiamata al
UseTwitterAuthentication
Configure
metodo nel metodo conUseAuthentication
:app.UseAuthentication();
Richiamare il
AddTwitter
metodo nelConfigureServices
metodo :services.AddAuthentication() .AddTwitter(options => { options.ConsumerKey = Configuration["auth:twitter:consumerkey"]; options.ConsumerSecret = Configuration["auth:twitter:consumersecret"]; });
Impostazione di schemi di autenticazione predefiniti
Nella versione 1.x le AutomaticAuthenticate
proprietà e AutomaticChallenge
della AuthenticationOptions classe base devono essere impostate su un singolo schema di autenticazione. Non c'era un buon modo per imporre questo.
Nella versione 2.0 queste due proprietà sono state rimosse come proprietà nella singola AuthenticationOptions
istanza. Possono essere configurati nella chiamata al AddAuthentication
metodo all'interno del ConfigureServices
metodo di Startup.cs
:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);
Nel frammento di codice precedente lo schema predefinito è impostato su CookieAuthenticationDefaults.AuthenticationScheme
("Cookie").
In alternativa, usare una versione di overload del AddAuthentication
metodo per impostare più proprietà. Nell'esempio di metodo di overload seguente, lo schema predefinito è impostato su CookieAuthenticationDefaults.AuthenticationScheme
. In alternativa, lo schema di autenticazione può essere specificato all'interno dei singoli [Authorize]
attributi o criteri di autorizzazione.
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
});
Definire uno schema predefinito nella versione 2.0 se una delle condizioni seguenti è vera:
- Si vuole che l'utente sia connesso automaticamente
- Usare i
[Authorize]
criteri di autorizzazione o attributo senza specificare schemi
Un'eccezione a questa regola è il AddIdentity
metodo . Questo metodo aggiunge cookie per l'utente e imposta gli schemi di autenticazione e verifica predefiniti per l'applicazione cookieIdentityConstants.ApplicationScheme
. Inoltre, imposta lo schema di accesso predefinito sull'oggetto esterno cookieIdentityConstants.ExternalScheme
.
Usare le estensioni di autenticazione HttpContext
L'interfaccia IAuthenticationManager
è il punto di ingresso principale nel sistema di autenticazione 1.x. È stato sostituito con un nuovo set di metodi di HttpContext
estensione nello spazio dei Microsoft.AspNetCore.Authentication
nomi .
Ad esempio, i progetti 1.x fanno riferimento a una Authentication
proprietà:
// Clear the existing external cookie to ensure a clean login process
await HttpContext.Authentication.SignOutAsync(_externalCookieScheme);
Nei progetti 2.0 importare lo Microsoft.AspNetCore.Authentication
spazio dei nomi ed eliminare i riferimenti alle Authentication
proprietà:
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
Autenticazione di Windows (HTTP.sys/IISIntegration)
Esistono due varianti di autenticazione di Windows:
L'host consente solo gli utenti autenticati. Questa variante non è influenzata dalle modifiche 2.0.
L'host consente sia utenti anonimi che autenticati. Questa variazione è influenzata dalle modifiche della versione 2.0. Ad esempio, l'app deve consentire utenti anonimi a livello iis o HTTP.sys , ma autorizzare gli utenti a livello di controller. In questo scenario, impostare lo schema predefinito nel
Startup.ConfigureServices
metodo .Per Microsoft.AspNetCore.Server.IISIntegration, impostare lo schema predefinito su
IISDefaults.AuthenticationScheme
:using Microsoft.AspNetCore.Server.IISIntegration; services.AddAuthentication(IISDefaults.AuthenticationScheme);
Per Microsoft.AspNetCore.Server.HttpSys, impostare lo schema predefinito su
HttpSysDefaults.AuthenticationScheme
:using Microsoft.AspNetCore.Server.HttpSys; services.AddAuthentication(HttpSysDefaults.AuthenticationScheme);
Se non si imposta lo schema predefinito, la richiesta di autorizzazione (richiesta di verifica) non funziona con l'eccezione seguente:
System.InvalidOperationException
: non è stato specificato alcun authenticationScheme e non è stato trovato DefaultChallengeScheme.
Per altre informazioni, vedere Configurare l'autenticazione di Windows in ASP.NET Core.
Istanze di IdentityCookieOptions
Un effetto collaterale delle modifiche 2.0 è il passaggio all'uso delle opzioni denominate anziché delle istanze di cookie opzioni. La possibilità di personalizzare i nomi degli Identitycookie schemi viene rimossa.
Ad esempio, i progetti 1.x usano l'inserimento del costruttore per passare un IdentityCookieOptions
parametro in AccountController.cs
e ManageController.cs
. È possibile accedere allo schema di autenticazione esterno cookie dall'istanza fornita:
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>();
}
L'inserimento del costruttore precedente non diventa necessario nei progetti 2.0 e il _externalCookieScheme
campo può essere eliminato:
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>();
}
1.x progetti usati nel _externalCookieScheme
campo come indicato di seguito:
// Clear the existing external cookie to ensure a clean login process
await HttpContext.Authentication.SignOutAsync(_externalCookieScheme);
Nei progetti 2.0 sostituire il codice precedente con il codice seguente. La IdentityConstants.ExternalScheme
costante può essere utilizzata direttamente.
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
Risolvere la chiamata appena aggiunta SignOutAsync
importando lo spazio dei nomi seguente:
using Microsoft.AspNetCore.Authentication;
Aggiungere le proprietà di navigazione IDENTITYUser POCO
Le proprietà di navigazione Entity Framework (EF) Core dell'oggetto IdentityUser
CLR semplice (Plain Old CLR Object) sono state rimosse. Se il progetto 1.x ha usato queste proprietà, aggiungerle manualmente al progetto 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>>();
Per evitare chiavi esterne duplicate durante l'esecuzione EF Core di Migrazioni, aggiungere quanto segue al IdentityDbContext
metodo della OnModelCreating
classe (dopo la base.OnModelCreating();
chiamata):
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);
}
Sostituire GetExternalAuthenticationSchemes
Il metodo GetExternalAuthenticationSchemes
sincrono è stato rimosso a favore di una versione asincrona. I progetti 1.x hanno il codice seguente in Controllers/ManageController.cs
:
var otherLogins = _signInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList();
Questo metodo viene visualizzato anche in Views/Account/Login.cshtml
:
@{
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>
}
}
Nei progetti 2.0 usare il GetExternalAuthenticationSchemesAsync metodo . La modifica in ManageController.cs
è simile al codice seguente:
var schemes = await _signInManager.GetExternalAuthenticationSchemesAsync();
var otherLogins = schemes.Where(auth => userLogins.All(ul => auth.Name != ul.LoginProvider)).ToList();
In Login.cshtml
la AuthenticationScheme
proprietà a cui si accede nel foreach
ciclo passa a 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>
}
}
Modifica della proprietà ManageLoginsViewModel
Un ManageLoginsViewModel
oggetto viene utilizzato nell'azione ManageLogins
di ManageController.cs
. Nei progetti 1.x il tipo restituito della proprietà dell'oggetto OtherLogins
è IList<AuthenticationDescription>
. Questo tipo restituito richiede un'importazione di 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; }
}
}
Nei progetti 2.0 il tipo restituito cambia in IList<AuthenticationScheme>
. Questo nuovo tipo restituito richiede la sostituzione dell'importazione Microsoft.AspNetCore.Http.Authentication
con un'importazione 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; }
}
}
Risorse aggiuntive
Per altre informazioni, vedere la discussione relativa al problema relativo all'autenticazione 2.0 in GitHub.