Introducción a Identity en ASP.NET Core

Por Rick Anderson

ASP.NET Core Identity:

  • Es una API que admite la funcionalidad de inicio de sesión de interfaz de usuario (UI).
  • Administra usuarios, contraseñas, datos de perfil, roles, notificaciones, tokens, confirmación de correo electrónico, etc.

Los usuarios pueden crear una cuenta con la información de inicio de sesión almacenada en Identity o pueden usar un proveedor de inicio de sesión externo. Entre los proveedores de inicios de sesión externos admitidos se incluyen Facebook, Google, cuenta Microsoft y Twitter.

Para obtener información sobre cómo requerir globalmente la autenticación de todos los usuarios, vea Requerir usuarios autenticados.

El Identity código fuente está disponible en GitHub. Scaffold Identity y ver los archivos generados para revisar la interacción de la plantilla con Identity .

Identitynormalmente se configura mediante una base SQL Server datos para almacenar nombres de usuario, contraseñas y datos de perfil. Como alternativa, se puede usar otro almacén persistente, por ejemplo, Azure Table Storage.

En este tema, aprenderá a usar para registrar, iniciar sesión y Identity cerrar la sesión de un usuario. Nota: Las plantillas tratan el nombre de usuario y el correo electrónico como los mismos para los usuarios. Para obtener instrucciones más detalladas sobre cómo crear aplicaciones que usan Identity , vea Pasos siguientes.

Plataforma de identidad de Microsoft es:

  • Una evolución de la plataforma Azure Active Directory desarrolladores de Azure Active Directory (Azure AD).
  • No relacionado con ASP.NET Core Identity .

ASP.NET Core Identity agrega la funcionalidad de inicio de sesión de la interfaz de usuario (IU) a las aplicaciones web de ASP.NET. Para proteger las API web y las SPA, use una de las siguientes opciones:

IdentityServer4 es un marco de OpenID Connect y OAuth 2.0 para ASP.NET Core. IdentityServer4 permite las siguientes características de seguridad:

  • Autenticación como servicio (AaaS)
  • Inicio de sesión único (SSO) mediante varios tipos de aplicaciones
  • Control de acceso para API
  • Federation Gateway

Para obtener más información, vea Welcome to IdentityServer4 (Bienvenida a Server4).

Vea o descargue el código de ejemplo (cómo descargar).

Creación de una aplicación web con autenticación

Cree un proyecto ASP.NET Core aplicación web con cuentas de usuario individuales.

  • Seleccione la ASP.NET Core aplicación web. Asigne al proyecto el nombre WebApp1 para que tenga el mismo espacio de nombres que la descarga del proyecto. Haga clic en OK.
  • En la entrada Tipo de autenticación, seleccione Cuentas de usuario individuales.

El proyecto generado proporciona ASP.NET Core Identity como biblioteca Razor de clases. La Identity Razor biblioteca de clases expone los puntos de conexión con el Identity área . Por ejemplo:

  • /Identity/Account/Login
  • /Identity/Account/Logout
  • /Identity/Account/Manage

Aplicación de migraciones

Aplique las migraciones para inicializar la base de datos.

Ejecute el siguiente comando en la consola Administrador de paquetes (PMC):

Update-Database

Prueba de registro e inicio de sesión

Ejecute la aplicación y registre un usuario. Según el tamaño de la pantalla, es posible que tenga que seleccionar el botón de alternancia de navegación para ver los vínculos Registrar e Iniciar sesión.

Visualización de la base de Identity datos

  • En el menú Ver, seleccione Explorador de objetos de SQL Server (SSOX).
  • Vaya a (localdb)MSSQLLocalDB(SQL Server 13). Haga clic con el botón derecho en dbo. Ver datos de AspNetUsers: >

Menú contextual de la tabla AspNetUsers en Explorador de objetos de SQL Server

Configuración de Identity servicios

Los servicios se agregan en Program.cs. El patrón típico es llamar a métodos en el orden siguiente:

  1. Add{Service}
  2. 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();

El código anterior se configura con Identity valores de opción predeterminados. Los servicios están disponibles para la aplicación a través de la inserción de dependencias.

Identity se habilita mediante una llamada a UseAuthentication. UseAuthentication agrega middleware de autenticación a la canalización de solicitudes.

La aplicación generada por plantilla no usa la autorización. app.UseAuthorization se incluye para asegurarse de que se agrega en el orden correcto si la aplicación agrega autorización. UseRoutingSe UseAuthentication debe llamar a , , y en el orden mostrado en el código UseAuthorization UseEndpoints anterior.

Para obtener más información sobre IdentityOptions , vea y Inicio de la IdentityOptions aplicación.

Scaffold Register, Login, LogOut y RegisterConfirmation

Agregue los Register archivos , , y Login LogOut RegisterConfirmation . Siga la identidad scaffolding en un Razor proyecto con instrucciones de autorización para generar el código que se muestra en esta sección.

Examen del registro

Cuando un usuario hace clic en el botón Registrar de la Register página, se invoca la RegisterModel.OnPostAsync acción. CreateAsync crea el usuario en el _userManager objeto :

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

Deshabilitación de la comprobación de la cuenta predeterminada

Con las plantillas predeterminadas, se redirige al usuario a donde puede seleccionar Account.RegisterConfirmation un vínculo para confirmar la cuenta. El valor Account.RegisterConfirmation predeterminado solo se usa para las pruebas; la comprobación automática de la cuenta debe deshabilitarse en una aplicación de producción.

Para requerir una cuenta confirmada e impedir el inicio de sesión inmediato en el registro, establezca en DisplayConfirmAccountLink = false Identity /Areas/ /Pages/Account/RegisterConfirmation.cshtml.cs:

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

Registro

El formulario Inicio de sesión se muestra cuando:

  • El vínculo Iniciar sesión está seleccionado.
  • Un usuario intenta acceder a una página restringida a la que no está autorizado para acceder o cuando el sistema no lo ha autenticado.

Cuando se envía el formulario en la página Inicio de sesión, se OnPostAsync llama a la acción . PasswordSignInAsync Se llama a en el _signInManager objeto .

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

Para obtener información sobre cómo tomar decisiones de autorización, vea Introducción a la autorización en ASP.NET Core .

Cerrar la sesión

El vínculo Cerrar sesión invoca la LogoutModel.OnPost acción.

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

En el código anterior, el código debe ser un redireccionamiento para que el explorador realice una nueva solicitud y se actualice la identidad return RedirectToPage(); del usuario.

SignOutAsync borra las notificaciones del usuario almacenadas en cookie .

Post se especifica en Pages/Shared/_LoginPartial.cshtml:

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

Prueba Identity

Las plantillas de proyecto web predeterminadas permiten el acceso anónimo a las páginas de inicio. Para probar Identity , agregue [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()
        {
        }
    }
}

Si ha iniciado sesión, cerrar sesión. Ejecute la aplicación y seleccione el Privacy vínculo. Se le redirige a la página de inicio de sesión.

Explorar Identity

Para explorar Identity con más detalle:

Identity Componentes

Todos los Identity paquetes de NuGet dependientes se incluyen en el marco ASP.NET Core compartido .

El paquete principal de Identity es Identity Microsoft.AspNetCore.. Este paquete contiene el conjunto principal de interfaces para ASP.NET Core Identity y lo incluye Microsoft.AspNetCore.Identity.EntityFrameworkCore .

Migración a ASP.NET Core Identity

Para obtener más información e instrucciones sobre cómo migrar el almacén Identity existente, vea Migrar autenticación y Identity .

Establecimiento de la seguridad de la contraseña

Consulte Configuración para obtener un ejemplo que establece los requisitos mínimos de contraseña.

AddDefault Identity y AddIdentity

AddDefaultIdentityse introdujo en ASP.NET Core 2.1. Llamar AddDefaultIdentity a es similar a llamar a lo siguiente:

Consulte AddDefault Identity source (Origen de AddDefault) para obtener más información.

Impedir la publicación de recursos Identity estáticos

Para evitar la publicación de recursos estáticos (hojas de estilos y archivos de JavaScript para la interfaz de usuario) en la raíz web, agregue la siguiente propiedad y destino al archivo de proyecto Identity Identity de la ResolveStaticWebAssetsInputsDependsOn RemoveIdentityAssets aplicación:

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

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

Pasos siguientes

Por Rick Anderson

ASP.NET Core Identity:

  • Es una API que admite la funcionalidad de inicio de sesión de la interfaz de usuario (UI).
  • Administra usuarios, contraseñas, datos de perfil, roles, notificaciones, tokens, confirmación de correo electrónico, etc.

Los usuarios pueden crear una cuenta con la información de inicio de sesión almacenada en Identity o pueden usar un proveedor de inicio de sesión externo. Entre los proveedores de inicios de sesión externos admitidos se incluyen Facebook, Google, cuenta Microsoft y Twitter.

Para obtener información sobre cómo requerir globalmente la autenticación de todos los usuarios, vea Requerir usuarios autenticados.

El Identity código fuente está disponible en GitHub. Scaffolding Identity y ver los archivos generados para revisar la interacción de la plantilla con Identity .

Identitynormalmente se configura mediante una base de SQL Server de datos para almacenar nombres de usuario, contraseñas y datos de perfil. Como alternativa, se puede usar otro almacén persistente, por ejemplo, Azure Table Storage.

En este tema, aprenderá a usar para registrar, iniciar sesión y Identity cerrar la sesión de un usuario. Nota: Las plantillas tratan el nombre de usuario y el correo electrónico como los mismos para los usuarios. Para obtener instrucciones más detalladas sobre cómo crear aplicaciones que usan Identity , vea Pasos siguientes.

Plataforma de identidad de Microsoft es:

  • Una evolución de la plataforma Azure Active Directory (Azure AD) desarrolladores.
  • No relacionado con ASP.NET Core Identity .

ASP.NET Core Identity agrega la funcionalidad de inicio de sesión de la interfaz de usuario (IU) a las aplicaciones web de ASP.NET. Para proteger las API web y las SPA, use una de las siguientes opciones:

IdentityServer4 es un marco de OpenID Connect y OAuth 2.0 para ASP.NET Core. IdentityServer4 permite las siguientes características de seguridad:

  • Autenticación como servicio (AaaS)
  • Inicio de sesión único (SSO) mediante varios tipos de aplicaciones
  • Control de acceso para API
  • Federation Gateway

Para obtener más información, vea Welcome to IdentityServer4 (Bienvenida a Server4).

Vea o descargue el código de ejemplo (cómo descargar).

Creación de una aplicación web con autenticación

Cree un proyecto ASP.NET Core aplicación web con cuentas de usuario individuales.

  • Seleccione Archivo > nuevo > Project.
  • Seleccione Aplicación web de ASP.NET Core. Asigne al proyecto el nombre WebApp1 para que tenga el mismo espacio de nombres que la descarga del proyecto. Haga clic en OK.
  • Seleccione una aplicación ASP.NET Core web y, a continuación, seleccione Cambiar autenticación.
  • Seleccione Cuentas de usuario individuales y haga clic en Aceptar.

El proyecto generado proporciona ASP.NET Core Identity como biblioteca Razor de clases. La Identity Razor biblioteca de clases expone los puntos de conexión con el Identity área . Por ejemplo:

  • /Identity/Account/Login
  • /Identity/Account/Logout
  • /Identity/Account/Manage

Aplicación de migraciones

Aplique las migraciones para inicializar la base de datos.

Ejecute el siguiente comando en Administrador de paquetes Console (PMC):

PM> Update-Database

Probar registro e inicio de sesión

Ejecute la aplicación y registre un usuario. Según el tamaño de la pantalla, es posible que tenga que seleccionar el botón de alternancia de navegación para ver los vínculos Registrar e Iniciar sesión.

Visualización de la base de Identity datos

  • En el menú Ver, seleccione Explorador de objetos de SQL Server (SSOX).
  • Vaya a (localdb)MSSQLLocalDB(SQL Server 13). Haga clic con el botón derecho en dbo. Ver datos de AspNetUsers: >

Menú contextual de la tabla AspNetUsers en Explorador de objetos de SQL Server

Configuración de Identity servicios

Los servicios se agregan en ConfigureServices . El patrón habitual consiste en llamar a todos los métodos Add{Service} y, luego, a todos los métodos services.Configure{Service}.

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

El código resaltado anterior se configura con Identity valores de opción predeterminados. Los servicios están disponibles para la aplicación a través de la inserción de dependencias.

Identity se habilita mediante una llamada a UseAuthentication . UseAuthentication agrega middleware de autenticación a la canalización de solicitudes.

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

El código anterior se configura con Identity valores de opción predeterminados. Los servicios están disponibles para la aplicación a través de la inserción de dependencias.

Identity se habilita mediante una llamada a UseAuthentication. UseAuthentication agrega middleware de autenticación a la canalización de solicitudes.

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

La aplicación generada por plantilla no usa la autorización. app.UseAuthorization se incluye para asegurarse de que se agrega en el orden correcto si la aplicación agrega autorización. UseRoutingSe UseAuthentication debe llamar a , , y en el orden mostrado en el código UseAuthorization UseEndpoints anterior.

Para obtener más información sobre IdentityOptions y , vea e Inicio de la Startup IdentityOptions aplicación.

Scaffolding Register, Login, LogOut y RegisterConfirmation

Agregue los Register archivos , , y Login LogOut RegisterConfirmation . Siga la identidad scaffolding en un Razor proyecto con instrucciones de autorización para generar el código que se muestra en esta sección.

Examen del registro

Cuando un usuario hace clic en el botón Registrar de la Register página, se invoca la RegisterModel.OnPostAsync acción. CreateAsync crea el usuario en el _userManager objeto :

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

Deshabilitación de la comprobación de la cuenta predeterminada

Con las plantillas predeterminadas, se redirige al usuario a donde puede seleccionar Account.RegisterConfirmation un vínculo para confirmar la cuenta. El valor Account.RegisterConfirmation predeterminado solo se usa para las pruebas; la comprobación automática de la cuenta debe deshabilitarse en una aplicación de producción.

Para requerir una cuenta confirmada e impedir el inicio de sesión inmediato en el registro, establezca en DisplayConfirmAccountLink = false Identity /Areas/ /Pages/Account/RegisterConfirmation.cshtml.cs:

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

Registro

El formulario Inicio de sesión se muestra cuando:

  • El vínculo Iniciar sesión está seleccionado.
  • Un usuario intenta acceder a una página restringida a la que no está autorizado para acceder o cuando el sistema no lo ha autenticado.

Cuando se envía el formulario de la página Inicio de sesión, se OnPostAsync llama a la acción . PasswordSignInAsync Se llama a en el _signInManager objeto .

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

Para obtener información sobre cómo tomar decisiones de autorización, vea Introducción a la autorización en ASP.NET Core .

Cerrar la sesión

El vínculo Cerrar sesión invoca la LogoutModel.OnPost acción.

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

En el código anterior, el código debe ser un redireccionamiento para que el explorador realice una nueva solicitud y se actualice la identidad return RedirectToPage(); del usuario.

SignOutAsync borra las notificaciones del usuario almacenadas en cookie .

Post se especifica en Pages/Shared/_LoginPartial.cshtml:

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

Prueba Identity

Las plantillas de proyecto web predeterminadas permiten el acceso anónimo a las páginas de inicio. Para probar Identity , agregue [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()
        {
        }
    }
}

Si ha iniciado sesión, no lo haga. Ejecute la aplicación y seleccione el Privacy vínculo. Se le redirige a la página de inicio de sesión.

Explorar Identity

Para explorar Identity con más detalle:

Identity Componentes

Todos los Identity paquetes de NuGet dependientes se incluyen en el marco ASP.NET Core compartido.

El paquete principal de Identity es Identity Microsoft.AspNetCore.. Este paquete contiene el conjunto principal de interfaces para ASP.NET Core Identity y lo incluye Microsoft.AspNetCore.Identity.EntityFrameworkCore .

Migración a ASP.NET Core Identity

Para obtener más información e instrucciones sobre cómo migrar el almacén Identity existente, vea Migrar la autenticación Identity y .

Establecimiento de la seguridad de la contraseña

Consulte Configuración para obtener un ejemplo que establece los requisitos mínimos de contraseña.

AddDefault Identity y AddIdentity

AddDefaultIdentityse introdujo en ASP.NET Core 2.1. Llamar AddDefaultIdentity a es similar a llamar a lo siguiente:

Consulte AddDefault Identity source (Origen de AddDefault) para obtener más información.

Impedir la publicación de recursos Identity estáticos

Para evitar la publicación de recursos estáticos (hojas de estilos y archivos de JavaScript para la interfaz de usuario) en la raíz web, agregue la siguiente propiedad y destino al archivo de proyecto Identity Identity de la ResolveStaticWebAssetsInputsDependsOn RemoveIdentityAssets aplicación:

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

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

Pasos siguientes