Adición de autenticación de identidad ASP.NET MVC5 a un proyecto existente

164

He visto muchas páginas similares en la web, pero la mayoría usa un nuevo proyecto en lugar de uno existente, o no tiene las características necesarias. Entonces, tengo un MVC 5proyecto existente y quiero integrar ASP.NET MVC5 Identity con las funciones de inicio de sesión, confirmación por correo electrónico y restablecimiento de contraseña .

Además de esto, también necesito crear todas las tablas necesarias en la base de datos, es decir, Usuario, Roles, grupos, etc. (utilizo EF Code First en mi proyecto). ¿Hay algún artículo o muestra que corresponda a estas necesidades? Cualquier sugerencia sería apreciada. Gracias por adelantado...

Jack
fuente
Qué gran queston y qué simple solución dada justo debajo. Me encantó leerlo y también necesitaba integrarme en mi proyecto existente.
Ishwor Khanal

Respuestas:

282

Configurar la identidad para su proyecto existente no es algo difícil. Debe instalar algún paquete NuGet y hacer una pequeña configuración.

Primero instale estos paquetes NuGet con Package Manager Console:

PM> Install-Package Microsoft.AspNet.Identity.Owin 
PM> Install-Package Microsoft.AspNet.Identity.EntityFramework
PM> Install-Package Microsoft.Owin.Host.SystemWeb 

Agregue una clase de usuario y con IdentityUserherencia:

public class AppUser : IdentityUser
{
    //add your custom properties which have not included in IdentityUser before
    public string MyExtraProperty { get; set; }  
}

Haz lo mismo para el papel:

public class AppRole : IdentityRole
{
    public AppRole() : base() { }
    public AppRole(string name) : base(name) { }
    // extra properties here 
}

Cambie a su DbContextpadre de DbContexta me IdentityDbContext<AppUser>gusta esto:

public class MyDbContext : IdentityDbContext<AppUser>
{
    // Other part of codes still same 
    // You don't need to add AppUser and AppRole 
    // since automatically added by inheriting form IdentityDbContext<AppUser>
}

Si usa la misma cadena de conexión y la migración habilitada, EF creará las tablas necesarias para usted.

Opcionalmente, puede ampliar UserManagerpara agregar la configuración y personalización que desee:

public class AppUserManager : UserManager<AppUser>
{
    public AppUserManager(IUserStore<AppUser> store)
        : base(store)
    {
    }

    // this method is called by Owin therefore this is the best place to configure your User Manager
    public static AppUserManager Create(
        IdentityFactoryOptions<AppUserManager> options, IOwinContext context)
    {
        var manager = new AppUserManager(
            new UserStore<AppUser>(context.Get<MyDbContext>()));

        // optionally configure your manager
        // ...

        return manager;
    }
}

Como la identidad se basa en OWIN, también debe configurar OWIN:

Agregue una clase a la App_Startcarpeta (o en cualquier otro lugar si lo desea). Esta clase es utilizada por OWIN. Esta será tu clase de inicio.

namespace MyAppNamespace
{
    public class IdentityConfig
    {
        public void Configuration(IAppBuilder app)
        {
            app.CreatePerOwinContext(() => new MyDbContext());
            app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);
            app.CreatePerOwinContext<RoleManager<AppRole>>((options, context) =>
                new RoleManager<AppRole>(
                    new RoleStore<AppRole>(context.Get<MyDbContext>())));

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Home/Login"),
            });
        }
    }
}

Casi hecho, simplemente agregue esta línea de código a su web.configarchivo para que OWIN pueda encontrar su clase de inicio.

<appSettings>
    <!-- other setting here -->
    <add key="owin:AppStartup" value="MyAppNamespace.IdentityConfig" />
</appSettings>

Ahora, en todo el proyecto, puede usar Identity como cualquier proyecto nuevo que VS ya haya instalado. Considere la acción de inicio de sesión, por ejemplo

[HttpPost]
public ActionResult Login(LoginViewModel login)
{
    if (ModelState.IsValid)
    {
        var userManager = HttpContext.GetOwinContext().GetUserManager<AppUserManager>();
        var authManager = HttpContext.GetOwinContext().Authentication;

        AppUser user = userManager.Find(login.UserName, login.Password);
        if (user != null)
        {
            var ident = userManager.CreateIdentity(user, 
                DefaultAuthenticationTypes.ApplicationCookie);
            //use the instance that has been created. 
            authManager.SignIn(
                new AuthenticationProperties { IsPersistent = false }, ident);
            return Redirect(login.ReturnUrl ?? Url.Action("Index", "Home"));
        }
    }
    ModelState.AddModelError("", "Invalid username or password");
    return View(login);
}

Puede hacer roles y agregar a sus usuarios:

public ActionResult CreateRole(string roleName)
{
    var roleManager=HttpContext.GetOwinContext().GetUserManager<RoleManager<AppRole>>();

    if (!roleManager.RoleExists(roleName))
        roleManager.Create(new AppRole(roleName));
    // rest of code
} 

También puede agregar un rol a un usuario, como este:

UserManager.AddToRole(UserManager.FindByName("username").Id, "roleName");

Al usarlo Authorize, podría proteger sus acciones o controladores:

[Authorize]
public ActionResult MySecretAction() {}

o

[Authorize(Roles = "Admin")]]
public ActionResult MySecretAction() {}

También puede instalar paquetes adicionales y configurarlos para que cumplan con sus requisitos, Microsoft.Owin.Security.Facebooksegún lo que desee.

Nota: No olvide agregar espacios de nombres relevantes a sus archivos:

using Microsoft.AspNet.Identity;
using Microsoft.Owin.Security;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Owin;

También puede ver mis otras respuestas como esta y esto para el uso avanzado de Identidad.

Sam Farajpour Ghamari
fuente
2
Ambas soluciones se parecen. He utilizado AppRoleel administrador de roles de Identity para clasificar a los usuarios. Y puesto que Roles y RoleManagerya se han puesto en práctica por sí misma identidad que no es necesario volver a escribir código ya implementado. Actualizaré la publicación para mostrarle cómo puede usar los roles. Y como dije antes, solo necesitas agregar AppUsery AppRoleentidades para inicializar Identidad. Al heredar su DbContextde IdentityDbContext<AppUser>todas las tablas necesarias, agregue su tabla. No necesita hacer nada, solo habilitar la migración.
Sam Farajpour Ghamari
2
Acabo de agregar algunos ejemplos de uso. Instalar Microsoft.AspNet.Identity.EntityFrameworken su dominio y otro para la interfaz de usuario.
Sam Farajpour Ghamari
2
1) No te preocupes por tu web.config. No reemplace el viejo. Lea esto para más información . Creo que tu MVC también se actualizó.
Sam Farajpour Ghamari
1
2) Hiciste bien. 3) no hay problema. Tendrás 5 mesas nuevas AspNetRoles AspNetUserClaims AspNetUserLogins AspNetUserRolesyAspNetUsers
Sam Farajpour Ghamari
3
Acabo de leer todos los comentarios que dejaste ayudando a Clint Eastwood, ¡Buen trabajo! El mundo necesita más personas como tú plusOne
Chef_Code
24

Esto es lo que hice para integrar Identity con una base de datos existente.

  1. Cree un proyecto MVC de muestra con la plantilla MVC. Esto tiene todo el código necesario para la implementación de Identity: Startup.Auth.cs, IdentityConfig.cs, código del controlador de cuenta, Manage Controller, modelos y vistas relacionadas.

  2. Instale los paquetes nuget necesarios para Identity y OWIN. Obtendrá una idea al ver las referencias en el proyecto de muestra y la respuesta de @Sam

  3. Copie todo este código a su proyecto existente. Tenga en cuenta que no olvide agregar la cadena de conexión "DefaultConnection" para que Identity se asigne a su base de datos. Compruebe la clase ApplicationDBContext en IdentityModel.cs donde encontrará la referencia a la cadena de conexión "DefaultConnection".

  4. Este es el script SQL que ejecuté en mi base de datos existente para crear las tablas necesarias:

    USE ["YourDatabse"]
    GO
    /****** Object:  Table [dbo].[AspNetRoles]    Script Date: 16-Aug-15 6:52:25 PM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[AspNetRoles](
    [Id] [nvarchar](128) NOT NULL,
    [Name] [nvarchar](256) NOT NULL,
    CONSTRAINT [PK_dbo.AspNetRoles] PRIMARY KEY CLUSTERED 
    (
      [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    GO
    /****** Object:  Table [dbo].[AspNetUserClaims]    Script Date: 16-Aug-15 6:52:25 PM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[AspNetUserClaims](
       [Id] [int] IDENTITY(1,1) NOT NULL,
       [UserId] [nvarchar](128) NOT NULL,
       [ClaimType] [nvarchar](max) NULL,
       [ClaimValue] [nvarchar](max) NULL,
    CONSTRAINT [PK_dbo.AspNetUserClaims] PRIMARY KEY CLUSTERED 
    (
       [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    
    GO
    /****** Object:  Table [dbo].[AspNetUserLogins]    Script Date: 16-Aug-15 6:52:25 PM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[AspNetUserLogins](
        [LoginProvider] [nvarchar](128) NOT NULL,
        [ProviderKey] [nvarchar](128) NOT NULL,
        [UserId] [nvarchar](128) NOT NULL,
    CONSTRAINT [PK_dbo.AspNetUserLogins] PRIMARY KEY CLUSTERED 
    (
        [LoginProvider] ASC,
        [ProviderKey] ASC,
        [UserId] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    GO
    /****** Object:  Table [dbo].[AspNetUserRoles]    Script Date: 16-Aug-15 6:52:25 PM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[AspNetUserRoles](
       [UserId] [nvarchar](128) NOT NULL,
       [RoleId] [nvarchar](128) NOT NULL,
    CONSTRAINT [PK_dbo.AspNetUserRoles] PRIMARY KEY CLUSTERED 
    (
        [UserId] ASC,
        [RoleId] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    GO
    /****** Object:  Table [dbo].[AspNetUsers]    Script Date: 16-Aug-15 6:52:25 PM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[AspNetUsers](
        [Id] [nvarchar](128) NOT NULL,
        [Email] [nvarchar](256) NULL,
        [EmailConfirmed] [bit] NOT NULL,
        [PasswordHash] [nvarchar](max) NULL,
        [SecurityStamp] [nvarchar](max) NULL,
        [PhoneNumber] [nvarchar](max) NULL,
        [PhoneNumberConfirmed] [bit] NOT NULL,
        [TwoFactorEnabled] [bit] NOT NULL,
        [LockoutEndDateUtc] [datetime] NULL,
        [LockoutEnabled] [bit] NOT NULL,
        [AccessFailedCount] [int] NOT NULL,
        [UserName] [nvarchar](256) NOT NULL,
    CONSTRAINT [PK_dbo.AspNetUsers] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    
     GO
     ALTER TABLE [dbo].[AspNetUserClaims]  WITH CHECK ADD  CONSTRAINT [FK_dbo.AspNetUserClaims_dbo.AspNetUsers_UserId] FOREIGN KEY([UserId])
     REFERENCES [dbo].[AspNetUsers] ([Id])
     ON DELETE CASCADE
     GO
     ALTER TABLE [dbo].[AspNetUserClaims] CHECK CONSTRAINT [FK_dbo.AspNetUserClaims_dbo.AspNetUsers_UserId]
     GO
     ALTER TABLE [dbo].[AspNetUserLogins]  WITH CHECK ADD  CONSTRAINT [FK_dbo.AspNetUserLogins_dbo.AspNetUsers_UserId] FOREIGN KEY([UserId])
     REFERENCES [dbo].[AspNetUsers] ([Id])
     ON DELETE CASCADE
     GO
     ALTER TABLE [dbo].[AspNetUserLogins] CHECK CONSTRAINT [FK_dbo.AspNetUserLogins_dbo.AspNetUsers_UserId]
     GO
     ALTER TABLE [dbo].[AspNetUserRoles]  WITH CHECK ADD  CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetRoles_RoleId] FOREIGN KEY([RoleId])
     REFERENCES [dbo].[AspNetRoles] ([Id])
     ON DELETE CASCADE
     GO
     ALTER TABLE [dbo].[AspNetUserRoles] CHECK CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetRoles_RoleId]
     GO
     ALTER TABLE [dbo].[AspNetUserRoles]  WITH CHECK ADD  CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetUsers_UserId] FOREIGN KEY([UserId])
     REFERENCES [dbo].[AspNetUsers] ([Id])
     ON DELETE CASCADE
     GO
     ALTER TABLE [dbo].[AspNetUserRoles] CHECK CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetUsers_UserId]
     GO
  5. Verifique y resuelva los errores restantes y ya está. La identidad se encargará del resto :)

Shyamal Parikh
fuente
1
Muchas gracias por su respuesta y buenas explicaciones. En realidad, pienso en usar otro enfoque, pero también lo intentaré. Votado +
Jack
2
Creo que este es un enfoque mucho más limpio
niico
3
Además de la clase Startup.Auth.cs, debe copiar el Startup.cs ubicado en la raíz del proyecto de muestra.
Padmika
Shyamal, ¿puedes agregar el Startup.cs del comentario de @ Padmika? Esto es importante.
Mike
4

Recomiendo IdentityServer . Este es un proyecto de .NET Foundation y cubre muchos temas sobre autenticación y autorización.

Visión general

IdentityServer es un marco basado en .NET / Katana y un componente hospedable que permite implementar el inicio de sesión único y el control de acceso para aplicaciones web modernas y API que utilizan protocolos como OpenID Connect y OAuth2. Admite una amplia gama de clientes como aplicaciones móviles, web, SPA y de escritorio y es extensible para permitir la integración en arquitecturas nuevas y existentes.

Para más información, p. Ej.

  • soporte para MembershipReboot y ASP.NET Identity basados ​​en almacenes de usuarios
  • soporte para middleware de autenticación Katana adicional (por ejemplo, Google, Twitter, Facebook, etc.)
  • soporte para la persistencia de configuración basada en EntityFramework
  • soporte para WS-Federation
  • extensibilidad

Consulte la documentación y la demostración .

TotPeRo
fuente
66
Deben considerarse los usos prácticos de IdentityServer antes de saltar ciegamente a una implementación de IdentityServer.
hanzolo el