Migrieren der Identity Authentifizierung zu ASP.NET Core 2.0

Von Scott Addie und Hao Kung

ASP.NET Core 2.0 verfügt über ein neues Modell für die Authentifizierung, das die Konfiguration Identity mithilfe von Diensten vereinfacht. ASP.NET Core 1.x-Anwendungen, die die Authentifizierung verwenden oder aktualisiert werden können, um das neue Modell wie Identity unten beschrieben zu verwenden.

Aktualisieren von Namespaces

In 1.x wurden Klassen wie IdentityRole und IdentityUser im -Namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore gefunden.

In 2.0 wurde der Microsoft.AspNetCore.Identity -Namespace die neue Startseite für mehrere solcher Klassen. Mit dem Identity Standardcode enthalten die betroffenen Klassen ApplicationUser und Startup . Passen Sie Ihre using Anweisungen an, um die betroffenen Verweise aufzulösen.

Middleware und Dienste für die Authentifizierung

In 1.x-Projekten wird die Authentifizierung über Middleware konfiguriert. Für jedes Authentifizierungsschema, das Sie unterstützen möchten, wird eine Middlewaremethode aufgerufen.

Im folgenden 1.x-Beispiel wird die Facebook-Authentifizierung Identity mit in Identity

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

In 2.0-Projekten wird die Authentifizierung über Dienste konfiguriert. Jedes Authentifizierungsschema wird in der ConfigureServices -Methode von ConfigureServices Die UseIdentity -Methode wird durch UseAuthentication ersetzt.

Im folgenden 2.0-Beispiel wird die Facebook-Authentifizierung Identity mit in Identity

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

Die -Methode fügt eine einzelne Middlewarekomponente für die Authentifizierung hinzu, die für die automatische Authentifizierung und die Verarbeitung von UseAuthentication Remoteauthentifizierungsanforderungen verantwortlich ist. Er ersetzt alle einzelnen Middlewarekomponenten durch eine einzelne, gemeinsame Middlewarekomponente.

Im Folgenden finden Sie 2.0-Migrationsanweisungen für jedes wichtige Authentifizierungsschema.

-basierte Cookie Authentifizierung

Wählen Sie eine der beiden folgenden Optionen aus, und nehmen Sie die erforderlichen Änderungen in Startup.cs vor:

  1. Verwenden cookie von mit Identity

    • Ersetzen UseIdentity Sie in der UseAuthentication -Methode durch Configure :

      app.UseAuthentication();
      
    • Rufen Sie die AddIdentity -Methode in der ConfigureServices -Methode auf, um die cookie Authentifizierungsdienste hinzuzufügen.

    • Rufen Sie optional die - oder ConfigureApplicationCookieConfigureExternalCookie -Methode in der ConfigureServices -Methode auf, um die Einstellungen Identitycookie zu optimieren.

      services.AddIdentity<ApplicationUser, IdentityRole>()
              .AddEntityFrameworkStores<ApplicationDbContext>()
              .AddDefaultTokenProviders();
      
      services.ConfigureApplicationCookie(options => options.LoginPath = "/Account/LogIn");
      
  2. Verwenden cookie von ohne Identity

    • Ersetzen Sie UseCookieAuthentication den Methodenaufruf in der Configure -Methode durch UseAuthentication :

      app.UseAuthentication();
      
    • Rufen Sie AddAuthentication die Methoden und in der AddCookie -Methode ConfigureServices auf:

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

JWT-Bearerauthentifizierung

Nehmen Sie die folgenden Änderungen in Startup.cs vor:

  • Ersetzen Sie UseJwtBearerAuthentication den Methodenaufruf in der Configure -Methode durch UseAuthentication :

    app.UseAuthentication();
    
  • Rufen Sie die AddJwtBearer -Methode in der ConfigureServices -Methode auf:

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.Audience = "http://localhost:5001/";
                options.Authority = "http://localhost:5000/";
            });
    

    In diesem Codeausschnitt wird nicht verwendet. Daher sollte das Standardschema festgelegt werden, Identity indem an JwtBearerDefaults.AuthenticationScheme die -Methode übergeben AddAuthentication wird.

OpenID Verbinden -Authentifizierung (OIDC)

Nehmen Sie die folgenden Änderungen in Startup.cs vor:

  • Ersetzen Sie UseOpenIdConnectAuthentication den Methodenaufruf in der Configure -Methode durch UseAuthentication :

    app.UseAuthentication();
    
  • Rufen Sie die AddOpenIdConnect -Methode in der ConfigureServices -Methode auf:

    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"];
    });
    
  • Ersetzen Sie PostLogoutRedirectUri die -Eigenschaft in OpenIdConnectOptions der Aktion durch SignedOutRedirectUri :

    .AddOpenIdConnect(options =>
    {
        options.SignedOutRedirectUri = "https://contoso.com";
    });
    

Facebook-Authentifizierung

Nehmen Sie die folgenden Änderungen in Startup.cs vor:

  • Ersetzen Sie UseFacebookAuthentication den Methodenaufruf in der Configure -Methode durch UseAuthentication :

    app.UseAuthentication();
    
  • Rufen Sie die AddFacebook -Methode in der ConfigureServices -Methode auf:

    services.AddAuthentication()
            .AddFacebook(options =>
            {
                options.AppId = Configuration["auth:facebook:appid"];
                options.AppSecret = Configuration["auth:facebook:appsecret"];
            });
    

Google-Authentifizierung

Nehmen Sie die folgenden Änderungen in Startup.cs vor:

  • Ersetzen Sie UseGoogleAuthentication den Methodenaufruf in der Configure -Methode durch UseAuthentication :

    app.UseAuthentication();
    
  • Rufen Sie die AddGoogle -Methode in der ConfigureServices -Methode auf:

    services.AddAuthentication()
            .AddGoogle(options =>
            {
                options.ClientId = Configuration["auth:google:clientid"];
                options.ClientSecret = Configuration["auth:google:clientsecret"];
            });
    

Authentifizierung über Microsoft-Konto

Weitere Informationen zur Authentifizierung Microsoft-Konto finden Sie in diesem GitHub Problem.

Nehmen Sie die folgenden Änderungen in Startup.cs vor:

  • Ersetzen Sie UseMicrosoftAccountAuthentication den Methodenaufruf in der Configure -Methode durch UseAuthentication :

    app.UseAuthentication();
    
  • Rufen Sie die AddMicrosoftAccount -Methode in der ConfigureServices -Methode auf:

    services.AddAuthentication()
            .AddMicrosoftAccount(options =>
            {
                options.ClientId = Configuration["auth:microsoft:clientid"];
                options.ClientSecret = Configuration["auth:microsoft:clientsecret"];
            });
    

Twitter-Authentifizierung

Nehmen Sie die folgenden Änderungen in Startup.cs vor:

  • Ersetzen Sie UseTwitterAuthentication den Methodenaufruf in der Configure -Methode durch UseAuthentication :

    app.UseAuthentication();
    
  • Rufen Sie die AddTwitter -Methode in der ConfigureServices -Methode auf:

    services.AddAuthentication()
            .AddTwitter(options =>
            {
                options.ConsumerKey = Configuration["auth:twitter:consumerkey"];
                options.ConsumerSecret = Configuration["auth:twitter:consumersecret"];
            });
    

Festlegen von Standardauthentifizierungsschemas

In 1.x sollten die Eigenschaften und der AuthenticationOptions-Basisklasse für ein AutomaticAuthenticateAutomaticChallengeAutomaticAuthenticate festgelegt werden. Es gab keine gute Möglichkeit, dies zu erzwingen.

In 2.0 wurden diese beiden Eigenschaften als Eigenschaften für die einzelne Instanz AuthenticationOptions entfernt. Sie können im Methodenaufruf in der AddAuthenticationConfigureServices -Methode von AddAuthentication

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);

Im obigen Codeausschnitt ist das Standardschema auf CookieAuthenticationDefaults.AuthenticationScheme (" Cookie s") festgelegt.

Alternativ können Sie eine überladene Version der -Methode AddAuthentication verwenden, um mehr als eine Eigenschaft zu setzen. Im folgenden Beispiel für eine überladene Methode wird das Standardschema auf CookieAuthenticationDefaults.AuthenticationScheme festgelegt. Das Authentifizierungsschema kann alternativ in Ihren einzelnen Attributen [Authorize] oder Autorisierungsrichtlinien angegeben werden.

services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
});

Definieren Sie ein Standardschema in 2.0, wenn eine der folgenden Bedingungen zutrifft:

  • Sie möchten, dass der Benutzer automatisch angemeldet wird.
  • Sie verwenden das Attribut [Authorize] oder autorisierungsrichtlinien, ohne Schemas anzugeben.

Eine Ausnahme von dieser Regel ist die AddIdentity -Methode. Diese Methode fügt cookie s für Sie hinzu und legt die Standardauthentifizierungs- und -challenge-Schemas für die Anwendung cookieIdentityConstants.ApplicationScheme fest. Darüber hinaus wird das Standard-Anmeldeschema auf das externe cookieIdentityConstants.ExternalScheme festgelegt.

Verwenden von HttpContext-Authentifizierungserweiterungen

Die IAuthenticationManager -Schnittstelle ist der Haupteinstiegspunkt in das 1.x-Authentifizierungssystem. Sie wurde durch einen neuen Satz von HttpContext Erweiterungsmethoden im -Namespace Microsoft.AspNetCore.Authentication ersetzt.

Beispielsweise verweisen 1.x-Projekte auf eine Authentication Eigenschaft:

// Clear the existing external cookie to ensure a clean login process
await HttpContext.Authentication.SignOutAsync(_externalCookieScheme);

Importieren Sie in 2.0-Projekten den Microsoft.AspNetCore.Authentication Namespace, und löschen Sie Authentication die Eigenschaftenverweise:

// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);

Windows-Authentifizierung (HTTP.sys/IISIntegration)

Es gibt zwei Varianten der Windows Authentifizierung:

  • Der Host lässt nur authentifizierte Benutzer zu. Diese Variation wird von den Änderungen in 2.0 nicht beeinflusst.

  • Der Host lässt sowohl anonyme als auch authentifizierte Benutzer zu. Diese Variation wird von den Änderungen in 2.0 beeinflusst. Beispielsweise sollte die App anonyme Benutzer auf IIS- oderHTTP.sysebene zulassen, aber Benutzer auf Controllerebene autorisieren. Legen Sie in diesem Szenario das Standardschema in der -Methode Startup.ConfigureServices fest.

    Legen Sie für Microsoft.AspNetCore.Server.IISIntegrationdas Standardschema auf fest:

    using Microsoft.AspNetCore.Server.IISIntegration;
    
    services.AddAuthentication(IISDefaults.AuthenticationScheme);
    

    Legen Sie für Microsoft.AspNetCore.Server.HttpSysdas Standardschema auf fest:

    using Microsoft.AspNetCore.Server.HttpSys;
    
    services.AddAuthentication(HttpSysDefaults.AuthenticationScheme);
    

    Wenn das Standardschema nicht festgelegt wird, wird verhindert, dass die Autorisierungsanforderung (Aufforderung) mit der folgenden Ausnahme funktioniert:

    System.InvalidOperationException: Es wurde keine authenticationScheme angegeben, und es wurde keine DefaultC gemäßgeScheme gefunden.

Weitere Informationen finden Sie unter Konfigurieren Windows-Authentifizierung in ASP.NET Core.

-options">

cookie options-instances">IdentityCookie Options-Instanzen

Ein Nebeneffekt der Änderungen in 2.0 ist die Umstellung auf die Verwendung benannter Optionen anstelle von cookie Optionsinstanzen. Die Möglichkeit zum Anpassen der Identitycookie Schemanamen wird entfernt.

Beispielsweise verwenden 1.x-Projekte die Konstruktorinjektion, um einen Parameter an AccountController.cs und ManageController.cs zu übergeben. Der Zugriff auf cookie das externe Authentifizierungsschema erfolgt über die bereitgestellte Instanz:

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

Die oben genannte Konstruktorinjektion wird in 2.0-Projekten nicht mehr benötigt, und _externalCookieScheme das Feld kann gelöscht werden:

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-Projekte haben das _externalCookieScheme Feld wie folgt verwendet:

// Clear the existing external cookie to ensure a clean login process
await HttpContext.Authentication.SignOutAsync(_externalCookieScheme);

Ersetzen Sie in 2.0-Projekten den vorangehenden Code durch Folgendes. Die IdentityConstants.ExternalScheme Konstante kann direkt verwendet werden.

// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);

Lösen Sie den neu SignOutAsync hinzugefügten Aufruf auf, indem Sie den folgenden Namespace importieren:

using Microsoft.AspNetCore.Authentication;

Hinzufügen von Identity Benutzer-POCO-Navigationseigenschaften

Die Entity Framework (EF) Core-Navigationseigenschaften des IdentityUser Basis-POCO (Plain Old CLR Object) wurden entfernt. Wenn Ihr 1.x-Projekt diese Eigenschaften verwendet hat, fügen Sie sie manuell wieder zum 2.0-Projekt hinzu:

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

Fügen Sie der -Methode Ihrer Klasse (nach dem Aufruf) Folgendes hinzu, um beim Ausführen von EF Core Migrationen doppelte Fremdschlüssel zu IdentityDbContextOnModelCreatingbase.OnModelCreating(); verhindern:

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

Ersetzen von GetExternalAuthenticationSchemes

Die synchrone Methode GetExternalAuthenticationSchemes wurde zugunsten einer asynchronen Version entfernt. 1.x-Projekte weisen den folgenden Code in Controllers/ManageController.cs auf:

var otherLogins = _signInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList();

Diese Methode wird auch in Views/Account/Login.cshtml angezeigt:

@{
    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>
    }
}

Verwenden Sie in 2.0-Projekten die GetExternalAuthenticationSchemesAsync -Methode. Die Änderung in ManageController.cs ähnelt dem folgenden Code:

var schemes = await _signInManager.GetExternalAuthenticationSchemesAsync();
var otherLogins = schemes.Where(auth => userLogins.All(ul => auth.Name != ul.LoginProvider)).ToList();

In Login.cshtmländert sich die Eigenschaft, auf die in der Schleife zugegriffen foreach wird, in 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>
    }
}

ManageLoginsViewModel-Eigenschaftsänderung

Ein ManageLoginsViewModel -Objekt wird in der ManageLogins Aktion von ManageLoginsViewModelverwendet. In 1.x-Projekten ist der Rückgabetyp der -Eigenschaft des Objekts OtherLoginsIList<AuthenticationDescription> . Für diesen Rückgabetyp ist ein Import von Microsoft.AspNetCore.Http.Authentication erforderlich:

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

In 2.0-Projekten ändert sich der Rückgabetyp in IList<AuthenticationScheme> . Für diesen neuen Rückgabetyp muss der Import durch einen Import ersetzt Microsoft.AspNetCore.Http.AuthenticationMicrosoft.AspNetCore.Authentication werden.

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

Zusätzliche Ressourcen

Weitere Informationen finden Sie unter Discussion for Auth 2.0 issue on GitHub (Diskussion zu Auth 2.0-Problem auf GitHub).