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

Scott Addie a Hao Jejich

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

Aktualizace oborů názvů

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

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

Ověřovací middleware a služby

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

Následující příklad 1.x konfiguruje ověřování přes Facebook v Identity souboru 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"]
    });
}

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

Následující příklad 2.0 konfiguruje ověřování přes Facebook v Identity souboru 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 přidá jednu ověřovací middlewarovou komponentu, která je zodpovědná za automatické ověřování a zpracování UseAuthentication žádostí o vzdálené ověření. Nahrazuje všechny jednotlivé komponenty middlewaru jednou běžnou komponentou middlewaru.

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

Vyberte jednu z následujících dvou možností a v souboru Startup.cs proveďte potřebné změny:

  1. Použití cookie s s Identity

    • Nahraďte UseIdentity UseAuthentication v Configure metodě za :

      app.UseAuthentication();
      
    • Vyvoláním AddIdentity metody v ConfigureServices metodě přidejte cookie ověřovací služby.

    • Volitelně můžete v metodě vyvolat metodu ConfigureApplicationCookie nebo ConfigureExternalCookie , abyste ConfigureServices upravili Identity cookie nastavení.

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

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

      app.UseAuthentication();
      
    • Vyvolání AddAuthentication metod AddCookie a 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";
              });
      

Ověřování pomocí beareru JWT

V souboru Startup.cs proveďte následující změny:

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

    app.UseAuthentication();
    
  • AddJwtBearerVyvolat metodu v ConfigureServices metodě :

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

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

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

V souboru Startup.cs proveďte následující změny:

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

    app.UseAuthentication();
    
  • AddOpenIdConnectVyvolat metodu 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"];
    });
    
  • Nahraďte PostLogoutRedirectUri vlastnost v akci OpenIdConnectOptions : SignedOutRedirectUri

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

Ověřování Facebooku

V souboru Startup.cs proveďte následující změny:

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

    app.UseAuthentication();
    
  • AddFacebookVyvolat metodu v ConfigureServices metodě :

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

Ověřování Googlu

V souboru Startup.cs proveďte následující změny:

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

    app.UseAuthentication();
    
  • AddGoogleVyvolat metodu 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í účet Microsoft najdete v tomto GitHub problému.

V souboru Startup.cs proveďte následující změny:

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

    app.UseAuthentication();
    
  • AddMicrosoftAccountVyvolat metodu v ConfigureServices metodě :

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

Ověřování Twitteru

V souboru Startup.cs proveďte následující změny:

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

    app.UseAuthentication();
    
  • AddTwitterVyvolat metodu 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í

Ve 1.x byly vlastnosti a základní třídy AuthenticationOptions nastaveny na AutomaticAuthenticate AutomaticChallenge jedno schéma ověřování. Nebyl žádný dobrý způsob, jak to vynutit.

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

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);

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

Alternativně můžete použít přetíženou verzi metody k AddAuthentication 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í je možné zadat také v rámci jednotlivých atributů [Authorize] nebo zásad autorizace.

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

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

  • Chcete, aby byl uživatel automaticky přihlášen.
  • Použijete atribut [Authorize] nebo zásady autorizace bez zadávání schémat.

Výjimkou z tohoto pravidla je AddIdentity metoda . Tato metoda pro cookie vás přidá y a nastaví výchozí schémata ověřování a výzvy pro aplikaci cookie IdentityConstants.ApplicationScheme . Kromě toho nastaví výchozí schéma přihlašování na externí cookie IdentityConstants.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. Byla nahrazena novou sadu rozšiřujících metod HttpContext v oboru Microsoft.AspNetCore.Authentication názvů .

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

V projektech 2.0 naimportujte obor Microsoft.AspNetCore.Authentication názvů a odstraňte Authentication odkazy na vlastnosti:

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

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

Existují dvě varianty ověřování Windows ověřování:

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

  • Hostitel umožňuje anonymní i ověřené uživatele. Tato varianta je ovlivněna změnami 2.0. Aplikace by například měla povolit anonymní uživatele ve službě IIS neboHTTP.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.IISIntegrationnastavte výchozí schéma na IISDefaults.AuthenticationScheme :

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

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

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

    Pokud se výchozí schéma nepovolí, zabráníte tomu, aby požadavek na autorizaci (výzvu) pracoval s následující výjimkou:

    System.InvalidOperationException: Nebyl zadán žádný parametr authenticationScheme a nebyl nalezen žádný parametr DefaultChallengeScheme.

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

IdentityCookieInstance možností

Vedlejším efektem 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 Identity cookie názvy schémat je odebrána.

Například projekty 1.x používají injektáž konstruktoru k předání parametru IdentityCookieOptions do souborů AccountController.cs a ManageController.cs. K cookie externímu schématu ověřování se přistupuje ze zadané 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 v projektech 2.0 nepotřebuje a _externalCookieScheme pole je možné 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žily _externalCookieScheme pole následujícím způsobem:

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

SignOutAsyncPomocí importu následujícího oboru názvů vyřešte nově přidané volání:

using Microsoft.AspNetCore.Authentication;

Přidat Identity vlastnosti navigace POCO uživatele

Byla odebrána základní navigační vlastnost Entity Framework (EF) základního IdentityUser POCO (prostý starý objekt CLR). Pokud váš projekt 1. x tyto vlastnosti používá, přidejte je ručně zpátky 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>>();

Chcete-li zabránit duplicitním cizím klíčům při spuštění EF Core migrace, přidejte následující do IdentityDbContext OnModelCreating metody Class (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 namísto asynchronní verze. projekty 1. x mají následující kód v Controllers/ManageController. cs:

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

Tato metoda se zobrazí v zobrazeních/účtech/přihlašovacích údajích. cshtml je 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 GetExternalAuthenticationSchemesAsync metodu. Změna v ManageController. cs 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();

V Login. cshtml se vlastnost, ke které se AuthenticationScheme přistupovalo v foreach smyčce, 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

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

V projektech 2,0 se návratový typ změní na IList<AuthenticationScheme> . Tento nový návratový typ vyžaduje nahrazení Microsoft.AspNetCore.Http.Authentication importu pomocí Microsoft.AspNetCore.Authentication importu.

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ší zdroje informací

Další informace najdete v diskuzi o potížích s ověřením 2,0 na GitHub.