Sdílet prostřednictvím


Migrace ověřování a Identity ASP.NET Core 2.0

Scott Addie a Hao Kung

ASP.NET Core 2.0 má nový model pro ověřování a Identity zjednodušuje konfiguraci pomocí služeb. ASP.NET aplikace Core 1.x, které používají ověřování, nebo Identity je možné je aktualizovat, aby používaly nový model, jak je uvedeno níže.

Aktualizace oborů názvů

V 1.x byly třídy jako a IdentityRoleIdentityUser byly nalezeny v Microsoft.AspNetCore.Identity.EntityFrameworkCore oboru názvů.

V roce 2.0 Microsoft.AspNetCore.Identity se obor názvů stal novým domovem pro několik takových tříd. S výchozím Identity kódem zahrnují ApplicationUser ovlivněné třídy a Startup. Upravte příkazy a vyřešte using ovlivněné odkazy.

Middleware a služby ověřování

V projektech 1.x se ověřování konfiguruje prostřednictvím middlewaru. Metoda middlewaru se vyvolá pro každé schéma ověřování, které chcete podporovat.

Následující příklad 1.x konfiguruje ověřování facebooku pomocí IdentityStartup.cspříkazu :

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

Ve 2.0 projektech se ověřování konfiguruje prostřednictvím služeb. Každé schéma ověřování je registrováno ConfigureServices v metodě Startup.cs. Metoda UseIdentity je nahrazena UseAuthentication.

Následující příklad 2.0 konfiguruje ověřování facebooku pomocí IdentityStartup.cspříkazu :

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 přidá jednu komponentu middlewaru ověřování, která zodpovídá za automatické ověřování a zpracování žádostí o vzdálené ověřování. Nahrazuje všechny jednotlivé komponenty middlewaru jednou, běžnou komponentou middlewaru.

Níže najdete pokyny pro migraci 2.0 pro každé hlavní schéma ověřování.

Vyberte jednu ze dvou možností níže a proveďte potřebné změny v Startup.cs:

  1. Použití cookies Identity

    • UseAuthentication Nahraďte UseIdentity metodouConfigure:

      app.UseAuthentication();
      
    • Vyvolání AddIdentity metody v ConfigureServices metodě pro přidání cookie ověřovacích služeb.

    • Volitelně můžete vyvolat metodu ConfigureApplicationCookie nebo ConfigureExternalCookie metodu ConfigureServices v metodě a upravit Identitycookie nastavení.

      services.AddIdentity<ApplicationUser, IdentityRole>()
              .AddEntityFrameworkStores<ApplicationDbContext>()
              .AddDefaultTokenProviders();
      
      services.ConfigureApplicationCookie(options => options.LoginPath = "/Account/LogIn");
      
  2. Použití cookies bez Identity

    • UseCookieAuthentication Nahraďte volání metody v Configure metodě UseAuthenticationza :

      app.UseAuthentication();
      
    • Vyvolání AddAuthentication metod a AddCookie metod v ConfigureServices metodě:

      // 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 Bearer Authentication

Proveďte následující změny v Startup.cs:

  • UseJwtBearerAuthentication Nahraďte volání metody v Configure metodě UseAuthenticationza :

    app.UseAuthentication();
    
  • Vyvolání AddJwtBearer metody v ConfigureServices metodě:

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

    Tento fragment kódu se nepoužívá Identity, takže výchozí schéma by mělo být nastaveno předáním JwtBearerDefaults.AuthenticationScheme metody AddAuthentication .

Ověřování openID Připojení (OIDC)

Proveďte následující změny v Startup.cs:

  • UseOpenIdConnectAuthentication Nahraďte volání metody v Configure metodě UseAuthenticationza :

    app.UseAuthentication();
    
  • Vyvolání AddOpenIdConnect metody v ConfigureServices metodě:

    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"];
    });
    
  • PostLogoutRedirectUri Vlastnost v OpenIdConnectOptions akci nahraďte :SignedOutRedirectUri

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

Ověřování pomocí Facebooku

Proveďte následující změny v Startup.cs:

  • UseFacebookAuthentication Nahraďte volání metody v Configure metodě UseAuthenticationza :

    app.UseAuthentication();
    
  • Vyvolání AddFacebook metody v ConfigureServices metodě:

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

Ověřování pomocí Googlu

Proveďte následující změny v Startup.cs:

  • UseGoogleAuthentication Nahraďte volání metody v Configure metodě UseAuthenticationza :

    app.UseAuthentication();
    
  • Vyvolání AddGoogle metody v ConfigureServices metodě:

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

Ověřování pomocí účtu Microsoft

Další informace o ověřování účtu Microsoft najdete v tomto problému s GitHubem.

Proveďte následující změny v Startup.cs:

  • UseMicrosoftAccountAuthentication Nahraďte volání metody v Configure metodě UseAuthenticationza :

    app.UseAuthentication();
    
  • Vyvolání AddMicrosoftAccount metody v ConfigureServices metodě:

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

Ověřování pomocí Twitteru

Proveďte následující změny v Startup.cs:

  • UseTwitterAuthentication Nahraďte volání metody v Configure metodě UseAuthenticationza :

    app.UseAuthentication();
    
  • Vyvolání AddTwitter metody v ConfigureServices metodě:

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

Nastavení výchozích schémat ověřování

V 1.x AutomaticAuthenticate byly a AutomaticChallenge vlastnosti AuthenticationOptions základní třídy určeny k nastavení v jednom schématu ověřování. Nebyl žádný dobrý způsob, jak to vynutit.

Ve verzi 2.0 byly tyto dvě vlastnosti odebrány jako vlastnosti v jednotlivých AuthenticationOptions instancích. Je možné je nakonfigurovat ve AddAuthentication volání metody v rámci ConfigureServices metody Startup.cs:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);

V předchozím fragmentu kódu je výchozí schéma nastavené na CookieAuthenticationDefaults.AuthenticationScheme ("Cookies").

Alternativně použijte přetíženou verzi AddAuthentication metody k nastavení více než jedné vlastnosti. V následujícím příkladu přetížené metody je výchozí schéma nastaveno na CookieAuthenticationDefaults.AuthenticationScheme. Schéma ověřování může být případně zadáno v rámci jednotlivých [Authorize] atributů nebo zásad autorizace.

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

Definujte výchozí schéma ve verzi 2.0, pokud platí jedna z následujících podmínek:

  • Chcete, aby se uživatel automaticky přihlásil.
  • Použijete zásady atributu [Authorize] nebo autorizace bez určení schémat.

Výjimkou tohoto pravidla je AddIdentity metoda. Tato metoda přidá cookiepro vás a nastaví výchozí schémata ověřování a výzvy pro aplikaci cookieIdentityConstants.ApplicationScheme. Kromě toho nastaví výchozí přihlašovací schéma na externí cookieIdentityConstants.ExternalScheme.

Použití rozšíření ověřování HttpContext

Rozhraní IAuthenticationManager je hlavním vstupním bodem do ověřovacího systému 1.x. V oboru názvů byla nahrazena novou sadou rozšiřujících HttpContext metod Microsoft.AspNetCore.Authentication .

Například projekty 1.x odkazují na Authentication vlastnost:

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

Ve 2.0 projektech importujte Microsoft.AspNetCore.Authentication obor názvů a odstraňte odkazy na Authentication vlastnost:

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

Ověřování systému Windows (HTTP.sys / IISIntegration)

Existují dvě varianty ověřování systému Windows:

  • Hostitel povoluje jenom ověřené uživatele. Tato varianta není ovlivněná změnami 2.0.

  • Hostitel umožňuje anonymním i ověřeným uživatelům. Tato varianta je ovlivněna změnami 2.0. Aplikace by například měla povolit anonymním uživatelům na vrstvě IIS nebo HTTP.sys , ale autorizovat uživatele na úrovni kontroleru. V tomto scénáři nastavte výchozí schéma v Startup.ConfigureServices metodě.

    Pro Microsoft.AspNetCore.Server.IISIntegration nastavte výchozí schéma na IISDefaults.AuthenticationScheme:

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

    Pro Microsoft.AspNetCore.Server.HttpSys nastavte výchozí schéma na HttpSysDefaults.AuthenticationScheme:

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

    Nastavení výchozího schématu zabrání autorizaci (výzvě) v práci s následující výjimkou:

    System.InvalidOperationException: Nebylo zadáno žádné ověřováníScheme a nebyl nalezen žádný DefaultChallengeScheme.

Další informace najdete v tématu Konfigurace ověřování systému Windows v ASP.NET Core.

IdentityCookieInstance možností

Vedlejším účinkem změn 2,0 je přepnutí na použití pojmenovaných možností místo cookie instancí možností. Možnost přizpůsobit Identitycookie názvy schématu je odebrána.

Například projekty 1.x používají injektáž konstruktoru k předání parametru IdentityCookieOptions do AccountController.cs a ManageController.cs. K schématu externího cookie ověřování se přistupuje z poskytnuté instance:

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

Výše uvedená injektáž konstruktoru se stává nepotřebnou ve 2.0 projektech a _externalCookieScheme pole lze odstranit:

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 používaly _externalCookieScheme pole takto:

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

V projektech 2.0 nahraďte předchozí kód následujícím kódem. Konstantu IdentityConstants.ExternalScheme lze použít přímo.

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

Vyřešte nově přidané SignOutAsync volání importem následujícího oboru názvů:

using Microsoft.AspNetCore.Authentication;

Přidání Identityvlastností navigace POCO uživatele

Byly odebrány vlastnosti navigace Entity Framework (EF) Core základního IdentityUser OBJEKTu POCO (Plain Old CLR Object). Pokud váš projekt 1.x použil tyto vlastnosti, přidejte je ručně zpět 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>>();

Pokud chcete zabránit duplicitním cizím klíčům při spuštění EF Core migrace, přidejte následující kód do metody třídy IdentityDbContextOnModelCreating (po base.OnModelCreating(); volání):

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

Nahradit GetExternalAuthenticationSchemes

Synchronní metoda GetExternalAuthenticationSchemes byla odebrána ve prospěch asynchronní verze. Projekty 1.x mají následující kód:Controllers/ManageController.cs

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

Tato metoda se zobrazuje Views/Account/Login.cshtml také:

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

V projektech 2.0 použijte metodu GetExternalAuthenticationSchemesAsync . ManageController.cs Změna se podobá následujícímu kódu:

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

Vlastnost Login.cshtml, ke které se AuthenticationScheme přistupuje ve foreach smyčce, se změní 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>
    }
}

Změna vlastnosti ManageLoginsViewModel

Objekt ManageLoginsViewModel se používá v ManageLogins akci .ManageController.cs V projektech 1.x je IList<AuthenticationDescription>návratový OtherLogins typ vlastnosti objektu . Tento návratový typ vyžaduje import: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; }
    }
}

Ve 2.0 projektech se návratový typ změní na IList<AuthenticationScheme>. Tento nový návratový typ vyžaduje nahrazení Microsoft.AspNetCore.Http.Authentication 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; }
    }
}

Další prostředky

Další informace najdete v diskuzi o problému s ověřováním 2.0 na GitHubu.