Dela via


Migrera autentisering och Identity till ASP.NET Core 2.0

Av Scott Addie och Hao Kung

ASP.NET Core 2.0 har en ny modell för autentisering och Identity som förenklar konfigurationen med hjälp av tjänster. ASP.NET Core 1.x-program som använder autentisering eller Identity kan uppdateras för att använda den nya modellen enligt beskrivningen nedan.

Uppdatera namnområden

I 1.x hittades klasser som sådana IdentityRole och IdentityUser i Microsoft.AspNetCore.Identity.EntityFrameworkCore namnområdet.

I 2.0 Microsoft.AspNetCore.Identity blev namnområdet det nya hemmet för flera av dessa klasser. Med standardkoden Identity inkluderas de berörda klasserna, inklusive ApplicationUser och Startup. Justera dina using instruktioner för att lösa de berörda referenserna.

Mellanprogram och tjänster för autentisering

I 1.x-projekt konfigureras autentiseringen via mellanprogram. En mellanprogramsmetod anropas för varje autentiseringsschema som du vill stödja.

Följande 1.x-exempel konfigurerar Facebook-autentisering med Identity i 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"]
    });
}

I 2.0-projekt konfigureras autentisering via tjänster. Varje autentiseringsschema registreras i ConfigureServices metoden Startup.cs. Metoden UseIdentity ersätts med UseAuthentication.

I följande 2.0-exempel konfigureras Facebook-autentisering med Identity i 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();
}

Metoden UseAuthentication lägger till en enda autentiseringskomponent för mellanprogram, som ansvarar för automatisk autentisering och hantering av fjärrautentiseringsbegäranden. Den ersätter alla enskilda mellanprogramskomponenter med en enda gemensam mellanprogramskomponent.

Nedan visas 2.0-migreringsinstruktioner för varje större autentiseringsschema.

Välj ett av de två alternativen nedan och gör de nödvändiga ändringarna i Startup.cs:

  1. Använd cookies med Identity

    • Ersätt UseIdentity med UseAuthentication i Configure -metoden:

      app.UseAuthentication();
      
    • Anropa AddIdentity-metoden i ConfigureServices-metoden för att lägga till cookie-autentiseringstjänster.

    • Du kan också anropa ConfigureApplicationCookie metoden eller ConfigureExternalCookie i ConfigureServices metoden för att justera Identitycookie inställningarna.

      services.AddIdentity<ApplicationUser, IdentityRole>()
              .AddEntityFrameworkStores<ApplicationDbContext>()
              .AddDefaultTokenProviders();
      
      services.ConfigureApplicationCookie(options => options.LoginPath = "/Account/LogIn");
      
  2. Använd cookies utan Identity

    • Ersätt metodanropet UseCookieAuthenticationConfigure i metoden med UseAuthentication:

      app.UseAuthentication();
      
    • Anropa AddAuthentication- och AddCookie-metoderna i ConfigureServices-metoden:

      // 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-ägarautentisering

Gör följande ändringar i Startup.cs:

  • Ersätt metodanropet UseJwtBearerAuthenticationConfigure i metoden med UseAuthentication:

    app.UseAuthentication();
    
  • Anropa AddJwtBearer-metoden i ConfigureServices-metoden:

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

    Det här kodfragmentet använder Identityinte , så standardschemat bör anges genom att skicka JwtBearerDefaults.AuthenticationScheme till AddAuthentication -metoden.

OIDC-autentisering (OpenID Connect)

Gör följande ändringar i Startup.cs:

  • Ersätt metodanropet UseOpenIdConnectAuthenticationConfigure i metoden med UseAuthentication:

    app.UseAuthentication();
    
  • Anropa AddOpenIdConnect-metoden i ConfigureServices-metoden:

    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"];
    });
    
  • Ersätt egenskapen PostLogoutRedirectUri i åtgärden OpenIdConnectOptions med SignedOutRedirectUri:

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

Facebook-autentisering

Gör följande ändringar i Startup.cs:

  • Ersätt metodanropet UseFacebookAuthenticationConfigure i metoden med UseAuthentication:

    app.UseAuthentication();
    
  • Anropa AddFacebook-metoden i ConfigureServices-metoden:

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

Google-autentisering

Gör följande ändringar i Startup.cs:

  • Ersätt metodanropet UseGoogleAuthenticationConfigure i metoden med UseAuthentication:

    app.UseAuthentication();
    
  • Anropa AddGoogle-metoden i ConfigureServices-metoden:

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

Autentisering med Microsoft-konto

Mer information om Microsoft-kontoautentisering finns i det här GitHub-problemet.

Gör följande ändringar i Startup.cs:

  • Ersätt metodanropet UseMicrosoftAccountAuthenticationConfigure i metoden med UseAuthentication:

    app.UseAuthentication();
    
  • Anropa AddMicrosoftAccount-metoden i ConfigureServices-metoden:

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

Twitter-autentisering

Gör följande ändringar i Startup.cs:

  • Ersätt metodanropet UseTwitterAuthenticationConfigure i metoden med UseAuthentication:

    app.UseAuthentication();
    
  • Anropa AddTwitter-metoden i ConfigureServices-metoden:

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

Ange standardautentiseringsscheman

I 1.x var basklassens AutomaticAuthenticateAutomaticChallenge egenskaper och AuthenticationOptions avsedda att anges i ett enda autentiseringsschema. Det fanns inget bra sätt att genomdriva detta.

I 2.0 har dessa två egenskaper tagits bort som egenskaper för den enskilda AuthenticationOptions instansen. De kan konfigureras i metodanropet AddAuthentication inom metoden ConfigureServices av Startup.cs:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);

I föregående kodfragment är standardschemat inställt på CookieAuthenticationDefaults.AuthenticationScheme ("Cookies").

Du kan också använda en överbelastad version av AddAuthentication metoden för att ange mer än en egenskap. I följande exempel på överlagrade metoder är standardschemat inställt på CookieAuthenticationDefaults.AuthenticationScheme. Autentiseringsschemat kan också anges inom dina enskilda [Authorize] attribut eller auktoriseringsprinciper.

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

Definiera ett standardschema i 2.0 om något av följande villkor är sant:

  • Du vill att användaren ska loggas in automatiskt
  • Du använder attribut- [Authorize] eller auktoriseringsprinciperna utan att ange scheman

Ett undantag från den här regeln är AddIdentity metoden. Den här metoden lägger till cookies åt dig och anger standardscheman för autentisering och utmaning till programmet cookieIdentityConstants.ApplicationScheme. Dessutom anger den standardinloggningsschemat till det externa cookieIdentityConstants.ExternalScheme.

Använda HttpContext-autentiseringstillägg

Gränssnittet IAuthenticationManager är den viktigaste startpunkten i 1.x-autentiseringssystemet. Den har ersatts med en ny uppsättning HttpContext tilläggsmetoder i Microsoft.AspNetCore.Authentication namnområdet.

Till exempel refererar 1.x-projekt till en Authentication egenskap:

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

I 2.0-projekt importerar du Microsoft.AspNetCore.Authentication namnområdet och tar bort egenskapsreferenserna Authentication :

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

Windows-autentisering (HTTP.sys/IISIntegration)

Det finns två varianter av Windows-autentisering:

  • Värden tillåter endast autentiserade användare. Den här varianten påverkas inte av 2.0-ändringarna.

  • Värden tillåter både anonyma och autentiserade användare. Den här varianten påverkas av 2.0-ändringarna. Appen bör till exempel tillåta anonyma användare på IIS - eller HTTP.sys-lagret men auktorisera användare på kontrollantnivå. I det här scenariot anger du standardschemat i Startup.ConfigureServices -metoden.

    För Microsoft.AspNetCore.Server.IISIntegration anger du standardschemat till IISDefaults.AuthenticationScheme:

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

    För Microsoft.AspNetCore.Server.HttpSys anger du standardschemat till HttpSysDefaults.AuthenticationScheme:

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

    Om standardschemat inte anges förhindrar det att begäran om auktorisering (utmaning) fungerar med följande undantag:

    System.InvalidOperationException: Inget autentiseringsschema angavs, och det gick inte att hitta standardutmaningsschema.

Mer information finns i Konfigurera Windows-autentisering i ASP.NET Core.

"IdentityCookieOptions"-instanser

En bieffekt av 2.0-ändringarna är växlingen till att använda namngivna alternativ i stället för cookie alternativinstanser. Möjligheten att anpassa schemanamnen Identitycookie tas bort.

Till exempel använder 1.x-projekt konstruktorinmatning för att skicka en IdentityCookieOptions parameter till AccountController.cs och ManageController.cs. Det externa cookie autentiseringsschemat nås från den angivna instansen:

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

Den ovan nämnda konstruktorinmatningen blir onödig i 2.0-projekt och fältet _externalCookieScheme kan tas bort:

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-projekt använde _externalCookieScheme-fältet följande sätt:

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

I 2.0-projekt ersätter du föregående kod med följande. Konstanten IdentityConstants.ExternalScheme kan användas direkt.

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

Lös det nyligen tillagda SignOutAsync anropet genom att importera följande namnområde:

using Microsoft.AspNetCore.Authentication;

Lägga till POCO-navigeringsegenskaper för IdentityUser

Entity Framework -kärnnavigeringsegenskaperna för bas-POCO IdentityUser (vanligt gammalt CLR-objekt) har tagits bort. Om ditt 1.x-projekt använde dessa egenskaper lägger du manuellt till dem i 2.0-projektet:

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

Om du vill förhindra duplicerade utländska nycklar när du kör EF Core-migreringar, lägg till följande i IdentityDbContext-klassens OnModelCreating-metod (efter base.OnModelCreating();-anropet):

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

Ersätt GetExternalAuthenticationSchemes

Den synkrona metoden GetExternalAuthenticationSchemes togs bort till förmån för en asynkron version. 1.x-projekt har följande kod i Controllers/ManageController.cs:

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

Den här metoden visas också i 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>
    }
}

Använd GetExternalAuthenticationSchemesAsync-metoden i 2.0-projekt. Ändringen i ManageController.cs liknar följande kod:

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

I Login.cshtmländras egenskapen AuthenticationScheme som används i loopen foreach till 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>
    }
}

Ändra egenskapen ManageLoginsViewModel

Ett ManageLoginsViewModel objekt används i ManageLogins åtgärden ManageController.cs. I 1.x-projekt är objektets OtherLogins-egenskaps returtyp IList<AuthenticationDescription>. Den här returtypen kräver en import av 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; }
    }
}

I 2.0-projekt ändras returtypen till IList<AuthenticationScheme>. Den här nya returtypen kräver att Microsoft.AspNetCore.Http.Authentication importen ersätts med en Microsoft.AspNetCore.Authentication import.

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

Ytterligare resurser

Mer information finns i Avsnittet om problem med Auth 2.0 på GitHub.