Einführung in Identity in ASP.NET Core

Von Rick Anderson

ASP.NET Core Identity:

  • Eine API, die die Anmeldefunktionalität der Benutzeroberfläche (UI) unterstützt.
  • Verwaltet Benutzer, Kennwörter, Profildaten, Rollen, Ansprüche, Token, E-Mail-Bestätigung und vieles mehr.

Benutzer können ein Konto mit den in Identity gespeicherten Anmeldeinformationen erstellen oder einen externen Anmeldeanbieter verwenden. Zu den unterstützten externen Anmeldeanbietern gehören Facebook, Google, Microsoft-Konto und Twitter.

Informationen dazu, wie global die Authentifizierung aller Benutzer angefordert werden kann, finden Sie unter Authentifizierte Benutzer erforderlich.

Der Identity Quellcode ist auf GitHub verfügbar. Gerüst Identity und zeigen Sie die generierten Dateien an, um die Vorlageninteraktion mit Identityzu überprüfen.

Identitywird in der Regel mit einer SQL Server Datenbank zum Speichern von Benutzernamen, Kennwörtern und Profildaten konfiguriert. Alternativ kann ein anderer persistenter Speicher verwendet werden, z. B. Azure Table Storage.

In diesem Thema erfahren Sie, wie Identity Sie einen Benutzer mit registrieren, anmelden und abmelden. Hinweis: In den Vorlagen werden Benutzername und E-Mail für Benutzer gleich behandelt. Ausführlichere Anweisungen zum Erstellen von Apps, die Identityverwenden, finden Sie unter Nächste Schritte.

Identity ASP.NET Core steht nicht im Zusammenhang mit dem Microsoft Identity Platform. Microsoft Identity Platform ist:

  • Eine Weiterentwicklung der Azure Active Directory-Entwicklerplattform (Azure AD).
  • Eine alternative Identitätslösung für die Authentifizierung und Autorisierung in ASP.NET Core Apps.

ASP.NET Core Identity fügt Benutzeroberflächen-Anmeldefunktionen zu ASP.NET Core-Web-Apps hinzu. Verwenden Sie zum Sichern von Web-APIs und SPAs eine der folgenden Optionen:

Duende Identity Server ist ein OpenID Connect- und OAuth 2.0-Framework für ASP.NET Core. Duende Identity Server ermöglicht die folgenden Sicherheitsfeatures:

  • Authentifizierung als Dienst
  • Einmaliges Anmelden und einmaliges Abmelden für mehrere Anwendungstypen
  • Zugriffssteuerung für APIs
  • Federation Gateway

Wichtig

Duende Software erhebt ggf. eine Lizenzgebühr für die Nutzung von Duende Identity Server in der Produktion. Weitere Informationen finden Sie unter Migrieren von ASP.NET Core 5.0 zu 6.0.

Weitere Informationen finden Sie in der Dokumentation zu Duende Identity Server (Website von Duende Software).

Zeigen Sie den Beispielcode an, oder laden Sie diesenherunter (Herunterladen).

Erstellen einer Web-App mit Authentifizierung

Erstellen Sie ein ASP.NET Core Webanwendungsprojekt mit individuellen Benutzerkonten.

  • Wählen Sie die Vorlage ASP.NET Core-Web-App aus. Nennen Sie das Projekt WebApp1 , um denselben Namespace wie der Projektdownload zu haben. Klicken Sie auf OK.
  • Wählen Sie in der Eingabe Authentifizierungstyp die Option Einzelne Benutzerkonten aus.

Das generierte Projekt stellt ASP.NET Core Identity als Klassenbibliothek bereitRazor. Die IdentityRazor Klassenbibliothek macht Endpunkte mit dem Identity Bereich verfügbar. Beispiel:

  • /Identity/Konto/Anmeldung
  • /Identity/Konto/Abmelden
  • /Identity/Konto/Verwalten

Anwenden von Migrationen

Wenden Sie die Migrationen an, um die Datenbank zu initialisieren.

Führen Sie den folgenden Befehl in der Paket-Manager-Konsole (PMC) aus:

Update-Database

Testregistrierung und -anmeldung

Führen Sie die App aus, und registrieren Sie einen Benutzer. Je nach Bildschirmgröße müssen Sie möglicherweise die Umschaltfläche für die Navigation auswählen, um die Links Registrieren und Anmelden anzuzeigen.

Anzeigen der Identity Datenbank

  • Wählen Sie im Menü Ansichtdie Option SQL Server Objekt-Explorer (SSOX) aus.
  • Navigieren Sie zu (localdb)MSSQLLocalDB(SQL Server 13). Klicken Sie mit der rechten Maustaste auf dbo. AspNetUsers-Ansichtsdaten>:

Kontextmenü der Tabelle

Konfigurieren von Identity Diensten

Dienste werden in Program.cshinzugefügt. Das typische Muster besteht darin, Methoden in der folgenden Reihenfolge aufzurufen:

  1. Add{Service}
  2. builder.Services.Configure{Service}
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebApp1.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

builder.Services.Configure<IdentityOptions>(options =>
{
    // Password settings.
    options.Password.RequireDigit = true;
    options.Password.RequireLowercase = true;
    options.Password.RequireNonAlphanumeric = true;
    options.Password.RequireUppercase = true;
    options.Password.RequiredLength = 6;
    options.Password.RequiredUniqueChars = 1;

    // Lockout settings.
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
    options.Lockout.MaxFailedAccessAttempts = 5;
    options.Lockout.AllowedForNewUsers = true;

    // User settings.
    options.User.AllowedUserNameCharacters =
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
    options.User.RequireUniqueEmail = false;
});

builder.Services.ConfigureApplicationCookie(options =>
{
    // Cookie settings
    options.Cookie.HttpOnly = true;
    options.ExpireTimeSpan = TimeSpan.FromMinutes(5);

    options.LoginPath = "/Identity/Account/Login";
    options.AccessDeniedPath = "/Identity/Account/AccessDenied";
    options.SlidingExpiration = true;
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();

app.Run();

Der vorangehende Code wird Identity mit Standardoptionswerten konfiguriert. Dienste werden der App durch Abhängigkeitsinjektion zur Verfügung gestellt.

Identity wird durch Aufrufen UseAuthenticationvon aktiviert. UseAuthentication fügt der Anforderungspipeline Authentifizierungsmiddleware hinzu.

Die von der Vorlage generierte App verwendet keine Autorisierung. app.UseAuthorization ist enthalten, um sicherzustellen, dass sie in der richtigen Reihenfolge hinzugefügt wird, wenn die App die Autorisierung hinzufügt. UseRouting, UseAuthenticationund UseAuthorization müssen in der im vorherigen Code gezeigten Reihenfolge aufgerufen werden.

Weitere Informationen zu IdentityOptionsfinden Sie unter IdentityOptions und Anwendungsstart.

Gerüst für Register, Login, LogOut und RegisterConfirmation

Fügen Sie die RegisterDateien , Login, LogOutund RegisterConfirmation hinzu. Folgen Sie der Gerüstidentität in ein Razor Projekt mit Autorisierungsanweisungen , um den in diesem Abschnitt gezeigten Code zu generieren.

Untersuchen des Registers

Wenn ein Benutzer auf der Seite auf die Register Schaltfläche Registrieren klickt, wird die RegisterModel.OnPostAsync Aktion aufgerufen. Der Benutzer wird von CreateAsync(TUser) für das _userManager -Objekt erstellt:

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");
    ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync())
                                          .ToList();
    if (ModelState.IsValid)
    {
        var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
        var result = await _userManager.CreateAsync(user, Input.Password);
        if (result.Succeeded)
        {
            _logger.LogInformation("User created a new account with password.");

            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            var callbackUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { area = "Identity", userId = user.Id, code = code },
                protocol: Request.Scheme);

            await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

            if (_userManager.Options.SignIn.RequireConfirmedAccount)
            {
                return RedirectToPage("RegisterConfirmation", 
                                      new { email = Input.Email });
            }
            else
            {
                await _signInManager.SignInAsync(user, isPersistent: false);
                return LocalRedirect(returnUrl);
            }
        }
        foreach (var error in result.Errors)
        {
            ModelState.AddModelError(string.Empty, error.Description);
        }
    }

    // If we got this far, something failed, redisplay form
    return Page();
}

Deaktivieren der Standardkontoüberprüfung

Mit den Standardvorlagen wird der Benutzer zu der Account.RegisterConfirmation umgeleitet, wo er einen Link auswählen kann, um das Konto bestätigen zu lassen. Die Standardeinstellung Account.RegisterConfirmation wird nur für Tests verwendet. Die automatische Kontoüberprüfung sollte in einer Produktions-App deaktiviert werden.

Um ein bestätigtes Konto zu verlangen und eine sofortige Anmeldung bei der Registrierung zu verhindern, legen Sie in /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.csfestDisplayConfirmAccountLink = false:

[AllowAnonymous]
public class RegisterConfirmationModel : PageModel
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly IEmailSender _sender;

    public RegisterConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender sender)
    {
        _userManager = userManager;
        _sender = sender;
    }

    public string Email { get; set; }

    public bool DisplayConfirmAccountLink { get; set; }

    public string EmailConfirmationUrl { get; set; }

    public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
    {
        if (email == null)
        {
            return RedirectToPage("/Index");
        }

        var user = await _userManager.FindByEmailAsync(email);
        if (user == null)
        {
            return NotFound($"Unable to load user with email '{email}'.");
        }

        Email = email;
        // Once you add a real email sender, you should remove this code that lets you confirm the account
        DisplayConfirmAccountLink = false;
        if (DisplayConfirmAccountLink)
        {
            var userId = await _userManager.GetUserIdAsync(user);
            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            EmailConfirmationUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
                protocol: Request.Scheme);
        }

        return Page();
    }
}

Anmelden

Das Anmeldeformular wird angezeigt, wenn:

  • Der Link Anmelden ist ausgewählt.
  • Ein Benutzer versucht, auf eine eingeschränkte Seite zuzugreifen, für die er nicht autorisiert ist oder für die er nicht vom System authentifiziert wurde.

Wenn das Formular auf der Anmeldeseite übermittelt wird, wird die OnPostAsync Aktion aufgerufen. PasswordSignInAsync wird für das _signInManager -Objekt aufgerufen.

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");

    if (ModelState.IsValid)
    {
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, 
        // set lockoutOnFailure: true
        var result = await _signInManager.PasswordSignInAsync(Input.Email,
                           Input.Password, Input.RememberMe, lockoutOnFailure: true);
        if (result.Succeeded)
        {
            _logger.LogInformation("User logged in.");
            return LocalRedirect(returnUrl);
        }
        if (result.RequiresTwoFactor)
        {
            return RedirectToPage("./LoginWith2fa", new
            {
                ReturnUrl = returnUrl,
                RememberMe = Input.RememberMe
            });
        }
        if (result.IsLockedOut)
        {
            _logger.LogWarning("User account locked out.");
            return RedirectToPage("./Lockout");
        }
        else
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return Page();
        }
    }

    // If we got this far, something failed, redisplay form
    return Page();
}

Informationen zum Treffen von Autorisierungsentscheidungen finden Sie unter Einführung in die Autorisierung in ASP.NET Core.

Abmelden

Der Link Abmelden ruft die LogoutModel.OnPost Aktion auf.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace WebApp1.Areas.Identity.Pages.Account
{
    [AllowAnonymous]
    public class LogoutModel : PageModel
    {
        private readonly SignInManager<IdentityUser> _signInManager;
        private readonly ILogger<LogoutModel> _logger;

        public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger)
        {
            _signInManager = signInManager;
            _logger = logger;
        }

        public void OnGet()
        {
        }

        public async Task<IActionResult> OnPost(string returnUrl = null)
        {
            await _signInManager.SignOutAsync();
            _logger.LogInformation("User logged out.");
            if (returnUrl != null)
            {
                return LocalRedirect(returnUrl);
            }
            else
            {
                return RedirectToPage();
            }
        }
    }
}

Im obigen Code muss der Code return RedirectToPage(); eine Umleitung sein, damit der Browser eine neue Anforderung ausführt und die Identität für den Benutzer aktualisiert wird.

SignOutAsync löscht die in einem cookiegespeicherten Ansprüche des Benutzers.

Post wird in Pages/Shared/_LoginPartial.cshtmlangegeben:

@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

<ul class="navbar-nav">
@if (SignInManager.IsSignedIn(User))
{
    <li class="nav-item">
        <a  class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" 
                                              title="Manage">Hello @User.Identity.Name!</a>
    </li>
    <li class="nav-item">
        <form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" 
                                  asp-route-returnUrl="@Url.Page("/", new { area = "" })" 
                                  method="post" >
            <button  type="submit" class="nav-link btn btn-link text-dark">Logout</button>
        </form>
    </li>
}
else
{
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register">Register</a>
    </li>
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
    </li>
}
</ul>

Test Identity

Die Standardmäßigen Webprojektvorlagen ermöglichen den anonymen Zugriff auf die Startseiten. Fügen Sie zum Testen Identityfolgendes hinzu [Authorize]:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;

namespace WebApp1.Pages
{
    [Authorize]
    public class PrivacyModel : PageModel
    {
        private readonly ILogger<PrivacyModel> _logger;

        public PrivacyModel(ILogger<PrivacyModel> logger)
        {
            _logger = logger;
        }

        public void OnGet()
        {
        }
    }
}

Wenn Sie angemeldet sind, melden Sie sich ab. Führen Sie die App aus, und wählen Sie den Privacy Link aus. Sie werden zur Anmeldeseite umgeleitet.

Erkunden Identity

Ausführlichere Informationen finden Sie Identity hier:

Identity Komponenten

Alle abhängigen IdentityNuGet-Pakete sind im ASP.NET Core freigegebenen Framework enthalten.

Das primäre Paket für Identity ist Microsoft.AspNetCore.Identity. Dieses Paket enthält den Kernsatz von Schnittstellen für ASP.NET Core Identityund ist in Microsoft.AspNetCore.Identity.EntityFrameworkCoreenthalten.

Migrieren zu ASP.NET Core Identity

Weitere Informationen und Anleitungen zum Migrieren Ihres vorhandenen Identity Speichers finden Sie unter Migrieren der Authentifizierung und Identity.

Festlegen der Kennwortstärke

Unter Konfiguration finden Sie ein Beispiel, in dem die Mindestkennwortanforderungen festgelegt werden.

AddDefaultIdentity und AddIdentity

AddDefaultIdentitywurde in ASP.NET Core 2.1 eingeführt. Der Aufruf AddDefaultIdentity ähnelt dem Aufrufen von Folgendem:

Weitere Informationen finden Sie unter AddDefault-QuelleIdentity.

Verhindern der Veröffentlichung statischer Identity Ressourcen

Um die Veröffentlichung statischer Identity Ressourcen (Stylesheets und JavaScript-Dateien für die Benutzeroberfläche) im Identity Webstamm zu verhindern, fügen Sie der Projektdatei der App die folgende ResolveStaticWebAssetsInputsDependsOn Eigenschaft und RemoveIdentityAssets das Ziel hinzu:

<PropertyGroup>
  <ResolveStaticWebAssetsInputsDependsOn>RemoveIdentityAssets</ResolveStaticWebAssetsInputsDependsOn>
</PropertyGroup>

<Target Name="RemoveIdentityAssets">
  <ItemGroup>
    <StaticWebAsset Remove="@(StaticWebAsset)" Condition="%(SourceId) == 'Microsoft.AspNetCore.Identity.UI'" />
  </ItemGroup>
</Target>

Nächste Schritte

Von Rick Anderson

ASP.NET Core Identity:

  • Eine API, die die Anmeldefunktionalität der Benutzeroberfläche (UI) unterstützt.
  • Verwaltet Benutzer, Kennwörter, Profildaten, Rollen, Ansprüche, Token, E-Mail-Bestätigung und vieles mehr.

Benutzer können ein Konto mit den in Identity gespeicherten Anmeldeinformationen erstellen oder einen externen Anmeldeanbieter verwenden. Zu den unterstützten externen Anmeldeanbietern gehören Facebook, Google, Microsoft-Konto und Twitter.

Informationen dazu, wie global die Authentifizierung aller Benutzer angefordert werden kann, finden Sie unter Authentifizierte Benutzer erforderlich.

Der Identity Quellcode ist auf GitHub verfügbar. Gerüst Identity und zeigen Sie die generierten Dateien an, um die Vorlageninteraktion mit Identityzu überprüfen.

Identitywird in der Regel mit einer SQL Server Datenbank zum Speichern von Benutzernamen, Kennwörtern und Profildaten konfiguriert. Alternativ kann ein anderer persistenter Speicher verwendet werden, z. B. Azure Table Storage.

In diesem Thema erfahren Sie, wie Identity Sie einen Benutzer mit registrieren, anmelden und abmelden. Hinweis: In den Vorlagen werden Benutzername und E-Mail für Benutzer gleich behandelt. Ausführlichere Anweisungen zum Erstellen von Apps, die Identityverwenden, finden Sie unter Nächste Schritte.

Microsoft Identity Platform ist:

  • Eine Weiterentwicklung der Azure Active Directory-Entwicklerplattform (Azure AD).
  • Eine alternative Identitätslösung für die Authentifizierung und Autorisierung in ASP.NET Core Apps.
  • Nicht im Zusammenhang mit ASP.NET Core Identity.

ASP.NET Core Identity fügt Benutzeroberflächen-Anmeldefunktionen zu ASP.NET Core-Web-Apps hinzu. Verwenden Sie zum Sichern von Web-APIs und SPAs eine der folgenden Optionen:

Duende IdentityServer ist ein OpenID Connect- und OAuth 2.0-Framework für ASP.NET Core. Duende IdentityServer ermöglicht die folgenden Sicherheitsfeatures:

  • Authentifizierung als Dienst
  • Einmaliges Anmelden und einmaliges Abmelden für mehrere Anwendungstypen
  • Zugriffssteuerung für APIs
  • Federation Gateway

Weitere Informationen finden Sie in der Übersicht über Duende IdentityServer.

Weitere Informationen zu anderen Authentifizierungsanbietern finden Sie unter Community-basierte OSS-Authentifizierungsoptionen für ASP.NET Core.

Zeigen Sie den Beispielcode an, oder laden Sie diesenherunter (Herunterladen).

Erstellen einer Web-App mit Authentifizierung

Erstellen Sie ein ASP.NET Core Webanwendungsprojekt mit individuellen Benutzerkonten.

  • Klicken Sie auf Datei>Neu>Projekt.
  • Wählen Sie ASP.NET Core-Webanwendung aus. Nennen Sie das Projekt WebApp1 , um denselben Namespace wie der Projektdownload zu haben. Klicken Sie auf OK.
  • Wählen Sie eine ASP.NET Core-Webanwendung und dann Authentifizierung ändern aus.
  • Wählen Sie Einzelne Benutzerkonten aus, und klicken Sie auf OK.

Das generierte Projekt stellt ASP.NET Core Identity als Klassenbibliothek bereitRazor. Die IdentityRazor Klassenbibliothek macht Endpunkte mit dem Identity Bereich verfügbar. Beispiel:

  • /Identity/Konto/Anmeldung
  • /Identity/Konto/Abmelden
  • /Identity/Konto/Verwalten

Anwenden von Migrationen

Wenden Sie die Migrationen an, um die Datenbank zu initialisieren.

Führen Sie den folgenden Befehl in der Paket-Manager-Konsole (PMC) aus:

PM> Update-Database

Registrieren und Anmelden testen

Führen Sie die App aus, und registrieren Sie einen Benutzer. Je nach Bildschirmgröße müssen Sie möglicherweise die Navigationsschaltfläche auswählen, um die Links Registrieren und Anmelden anzuzeigen.

Anzeigen der Identity Datenbank

  • Wählen Sie im Menü Ansichtdie Option SQL Server Objekt-Explorer (SSOX) aus.
  • Navigieren Sie zu (localdb)MSSQLLocalDB(SQL Server 13). Klicken Sie mit der rechten Maustaste auf dbo. AspNetUsers-Daten>anzeigen:

Kontextmenü in der Tabelle AspNetUsers in SQL Server Objekt-Explorer

Konfigurieren von Identity Diensten

Dienste werden in ConfigureServiceshinzugefügt. Das typische Muster besteht darin, alle Add{Service}-Methoden und dann alle services.Configure{Service}-Methoden aufzurufen.

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
     // options.UseSqlite(
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));
    services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    services.AddRazorPages();

    services.Configure<IdentityOptions>(options =>
    {
        // Password settings.
        options.Password.RequireDigit = true;
        options.Password.RequireLowercase = true;
        options.Password.RequireNonAlphanumeric = true;
        options.Password.RequireUppercase = true;
        options.Password.RequiredLength = 6;
        options.Password.RequiredUniqueChars = 1;

        // Lockout settings.
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
        options.Lockout.MaxFailedAccessAttempts = 5;
        options.Lockout.AllowedForNewUsers = true;

        // User settings.
        options.User.AllowedUserNameCharacters =
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
        options.User.RequireUniqueEmail = false;
    });

    services.ConfigureApplicationCookie(options =>
    {
        // Cookie settings
        options.Cookie.HttpOnly = true;
        options.ExpireTimeSpan = TimeSpan.FromMinutes(5);

        options.LoginPath = "/Identity/Account/Login";
        options.AccessDeniedPath = "/Identity/Account/AccessDenied";
        options.SlidingExpiration = true;
    });
}

Der oben hervorgehobene Code wird mit Standardwerten Identity für Optionen konfiguriert. Dienste werden der App durch Abhängigkeitsinjektion zur Verfügung gestellt.

Identity wird durch Aufrufen UseAuthenticationvon aktiviert. UseAuthentication fügt der Anforderungspipeline Authentifizierungs-Middleware hinzu.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        // options.UseSqlite(
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));
    services.AddDatabaseDeveloperPageExceptionFilter();
    services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    services.AddRazorPages();

    services.Configure<IdentityOptions>(options =>
    {
        // Password settings.
        options.Password.RequireDigit = true;
        options.Password.RequireLowercase = true;
        options.Password.RequireNonAlphanumeric = true;
        options.Password.RequireUppercase = true;
        options.Password.RequiredLength = 6;
        options.Password.RequiredUniqueChars = 1;

        // Lockout settings.
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
        options.Lockout.MaxFailedAccessAttempts = 5;
        options.Lockout.AllowedForNewUsers = true;

        // User settings.
        options.User.AllowedUserNameCharacters =
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
        options.User.RequireUniqueEmail = false;
    });

    services.ConfigureApplicationCookie(options =>
    {
        // Cookie settings
        options.Cookie.HttpOnly = true;
        options.ExpireTimeSpan = TimeSpan.FromMinutes(5);

        options.LoginPath = "/Identity/Account/Login";
        options.AccessDeniedPath = "/Identity/Account/AccessDenied";
        options.SlidingExpiration = true;
    });
}

Der vorherige Code wird mit Standardwerten Identity für Optionen konfiguriert. Dienste werden der App durch Abhängigkeitsinjektion zur Verfügung gestellt.

Identity wird durch Aufrufen UseAuthenticationvon aktiviert. UseAuthentication fügt der Anforderungspipeline Authentifizierungs-Middleware hinzu.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseMigrationsEndPoint();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Die vorlagegenerierte App verwendet keine Autorisierung. app.UseAuthorization ist enthalten, um sicherzustellen, dass sie in der richtigen Reihenfolge hinzugefügt wird, wenn die App die Autorisierung hinzufügt. UseRouting, UseAuthentication, UseAuthorizationund UseEndpoints müssen in der reihenfolge aufgerufen werden, die im vorherigen Code dargestellt ist.

Weitere Informationen zu IdentityOptions und Startupfinden Sie unter IdentityOptionsund Anwendungsstart.

Scaffold Register, Login, LogOut und RegisterConfirmation

Fügen Sie die RegisterDateien , Login, LogOutund RegisterConfirmation hinzu. Befolgen Sie die Gerüstidentität in einem Razor Projekt mit Autorisierungsanweisungen , um den in diesem Abschnitt gezeigten Code zu generieren.

Register untersuchen

Wenn ein Benutzer auf der Seite auf die Register Schaltfläche Registrieren klickt, wird die RegisterModel.OnPostAsync Aktion aufgerufen. Der Benutzer wird von CreateAsync(TUser) für das _userManager Objekt erstellt:

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");
    ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync())
                                          .ToList();
    if (ModelState.IsValid)
    {
        var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
        var result = await _userManager.CreateAsync(user, Input.Password);
        if (result.Succeeded)
        {
            _logger.LogInformation("User created a new account with password.");

            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            var callbackUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { area = "Identity", userId = user.Id, code = code },
                protocol: Request.Scheme);

            await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

            if (_userManager.Options.SignIn.RequireConfirmedAccount)
            {
                return RedirectToPage("RegisterConfirmation", 
                                      new { email = Input.Email });
            }
            else
            {
                await _signInManager.SignInAsync(user, isPersistent: false);
                return LocalRedirect(returnUrl);
            }
        }
        foreach (var error in result.Errors)
        {
            ModelState.AddModelError(string.Empty, error.Description);
        }
    }

    // If we got this far, something failed, redisplay form
    return Page();
}

Deaktivieren der Standardkontoüberprüfung

Bei den Standardvorlagen wird der Benutzer an die Stelle weitergeleitet, in der Account.RegisterConfirmation er einen Link auswählen kann, um das Konto bestätigen zu lassen. Der Standardwert Account.RegisterConfirmation wird nur für Tests verwendet. Die automatische Kontoüberprüfung sollte in einer Produktions-App deaktiviert werden.

Um ein bestätigtes Konto zu erfordern und eine sofortige Anmeldung bei der Registrierung zu verhindern, legen Sie folgendes /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.csfestDisplayConfirmAccountLink = false:

[AllowAnonymous]
public class RegisterConfirmationModel : PageModel
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly IEmailSender _sender;

    public RegisterConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender sender)
    {
        _userManager = userManager;
        _sender = sender;
    }

    public string Email { get; set; }

    public bool DisplayConfirmAccountLink { get; set; }

    public string EmailConfirmationUrl { get; set; }

    public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
    {
        if (email == null)
        {
            return RedirectToPage("/Index");
        }

        var user = await _userManager.FindByEmailAsync(email);
        if (user == null)
        {
            return NotFound($"Unable to load user with email '{email}'.");
        }

        Email = email;
        // Once you add a real email sender, you should remove this code that lets you confirm the account
        DisplayConfirmAccountLink = false;
        if (DisplayConfirmAccountLink)
        {
            var userId = await _userManager.GetUserIdAsync(user);
            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            EmailConfirmationUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
                protocol: Request.Scheme);
        }

        return Page();
    }
}

Anmelden

Das Anmeldeformular wird in folgenden Fällen angezeigt:

  • Der Link Anmelden ist ausgewählt.
  • Ein Benutzer versucht, auf eine eingeschränkte Seite zuzugreifen, für die er nicht autorisiert ist oder für die er nicht vom System authentifiziert wurde.

Wenn das Formular auf der Anmeldeseite übermittelt wird, wird die OnPostAsync Aktion aufgerufen. PasswordSignInAsync wird für das _signInManager -Objekt aufgerufen.

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");

    if (ModelState.IsValid)
    {
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, 
        // set lockoutOnFailure: true
        var result = await _signInManager.PasswordSignInAsync(Input.Email,
                           Input.Password, Input.RememberMe, lockoutOnFailure: true);
        if (result.Succeeded)
        {
            _logger.LogInformation("User logged in.");
            return LocalRedirect(returnUrl);
        }
        if (result.RequiresTwoFactor)
        {
            return RedirectToPage("./LoginWith2fa", new
            {
                ReturnUrl = returnUrl,
                RememberMe = Input.RememberMe
            });
        }
        if (result.IsLockedOut)
        {
            _logger.LogWarning("User account locked out.");
            return RedirectToPage("./Lockout");
        }
        else
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return Page();
        }
    }

    // If we got this far, something failed, redisplay form
    return Page();
}

Informationen zum Treffen von Autorisierungsentscheidungen finden Sie unter Einführung in die Autorisierung in ASP.NET Core.

Abmelden

Der Link Abmelden ruft die LogoutModel.OnPost Aktion auf.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace WebApp1.Areas.Identity.Pages.Account
{
    [AllowAnonymous]
    public class LogoutModel : PageModel
    {
        private readonly SignInManager<IdentityUser> _signInManager;
        private readonly ILogger<LogoutModel> _logger;

        public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger)
        {
            _signInManager = signInManager;
            _logger = logger;
        }

        public void OnGet()
        {
        }

        public async Task<IActionResult> OnPost(string returnUrl = null)
        {
            await _signInManager.SignOutAsync();
            _logger.LogInformation("User logged out.");
            if (returnUrl != null)
            {
                return LocalRedirect(returnUrl);
            }
            else
            {
                return RedirectToPage();
            }
        }
    }
}

Im vorherigen Code muss der Code return RedirectToPage(); eine Umleitung sein, damit der Browser eine neue Anforderung ausführt und die Identität für den Benutzer aktualisiert wird.

SignOutAsync löscht die Ansprüche des Benutzers, die in gespeichert cookiesind.

Post wird in Pages/Shared/_LoginPartial.cshtmlangegeben:

@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

<ul class="navbar-nav">
@if (SignInManager.IsSignedIn(User))
{
    <li class="nav-item">
        <a  class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" 
                                              title="Manage">Hello @User.Identity.Name!</a>
    </li>
    <li class="nav-item">
        <form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" 
                                  asp-route-returnUrl="@Url.Page("/", new { area = "" })" 
                                  method="post" >
            <button  type="submit" class="nav-link btn btn-link text-dark">Logout</button>
        </form>
    </li>
}
else
{
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register">Register</a>
    </li>
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
    </li>
}
</ul>

Test Identity

Die Standardvorlagen für Webprojekte ermöglichen den anonymen Zugriff auf die Startseiten. Fügen Sie zum Testen IdentityFolgendes hinzu [Authorize]:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;

namespace WebApp1.Pages
{
    [Authorize]
    public class PrivacyModel : PageModel
    {
        private readonly ILogger<PrivacyModel> _logger;

        public PrivacyModel(ILogger<PrivacyModel> logger)
        {
            _logger = logger;
        }

        public void OnGet()
        {
        }
    }
}

Wenn Sie angemeldet sind, melden Sie sich ab. Führen Sie die App aus, und wählen Sie den Privacy Link aus. Sie werden zur Anmeldeseite umgeleitet.

Erkunden Identity

So erkunden Sie Identity folgendes:

Identity Komponenten

Alle abhängigen IdentityNuGet-Pakete sind im ASP.NET Core freigegebenen Frameworks enthalten.

Das primäre Paket für Identity ist Microsoft.AspNetCore.Identity. Dieses Paket enthält den Kernsatz von Schnittstellen für ASP.NET Core Identityund ist in Microsoft.AspNetCore.Identity.EntityFrameworkCoreenthalten.

Migrieren zu ASP.NET Core Identity

Weitere Informationen und Anleitungen zum Migrieren Ihres vorhandenen Identity Speichers finden Sie unter Migrieren der Authentifizierung und Identity.

Festlegen der Kennwortstärke

Ein Beispiel, das die Mindestkennwortanforderungen festlegt, finden Sie unter Konfiguration .

AddDefaultIdentity und AddIdentity

AddDefaultIdentitywurde in ASP.NET Core 2.1 eingeführt. Der Aufruf AddDefaultIdentity ähnelt dem Aufrufen von Folgendem:

Weitere Informationen finden Sie unter AddDefaultIdentity source .

Verhindern der Veröffentlichung statischer Identity Ressourcen

Um die Veröffentlichung statischer Identity Ressourcen (Stylesheets und JavaScript-Dateien für die Benutzeroberfläche) im Identity Webstamm zu verhindern, fügen Sie der Projektdatei der App die folgende ResolveStaticWebAssetsInputsDependsOn Eigenschaft und RemoveIdentityAssets das Ziel hinzu:

<PropertyGroup>
  <ResolveStaticWebAssetsInputsDependsOn>RemoveIdentityAssets</ResolveStaticWebAssetsInputsDependsOn>
</PropertyGroup>

<Target Name="RemoveIdentityAssets">
  <ItemGroup>
    <StaticWebAsset Remove="@(StaticWebAsset)" Condition="%(SourceId) == 'Microsoft.AspNetCore.Identity.UI'" />
  </ItemGroup>
</Target>

Nächste Schritte