¿Cómo uso mi propia base de datos con SimpleMembership y WebSecurity? ¿De qué se trata la seguridad de MVC4?

He leído todo sobre este tema que pude encontrar, incluidos los artículos de MSDN y las publicaciones de SO, pero todavía estoy perdido y confundido.

Preguntas

Por favor responda lo siguiente (brevemente, si es posible):

  1. ¿Qué es SimpleMembership / SimpleMembershipProvider ( WebMatrix.WebData ) y de qué es / son responsables?

  2. ¿Qué es WebSecurity ( WebMatrix.WebData )?

  3. ¿Qué es la clase de membresía ( System.Web.Security )?

  4. ¿Por qué MVC4 crea una tabla de Perfil de usuario y una tabla de páginas web_Membresía? ¿Para qué son y cuál es la diferencia? ¿Cuál es la clase UserProfile que crea MVC4?

  5. ¿Cuál es la clase UsersContext ?

  6. ¿Cómo funcionan todos estos para hacer la autenticación de usuario?

Mi situación

Estas preguntas luego conducen al siguiente problema:

Supongamos que tengo una base de datos existente con usuarios (ID, nombres de usuario, contraseñas). Estoy creando una nueva aplicación MVC4 y utilizando la Autenticación de formularios. Las contraseñas de los usuarios se almacenan en la base de datos en forma cifrada (no bcrypt).

¿Qué tengo que hacer para que funcione con MVC4?

¿Debo crear un MembershipProvider personalizado?

Mi conocimiento hasta ahora

Por lo que puedo entender, WebSecurity es una clase estática (Módulo) que interactúa con MembershipProvider . Un MembershipProvider es una clase que explica cómo funcionan determinadas funciones, como ValidateUser , CreateUser , ChangePassword .

Para resolver mi problema, supongo que necesito crear un MembershipProvider personalizado y decirle a WebSecurity que use mi nuevo MembershipProvider.

¿Generosidad?

He puesto una recompensa en esta pregunta y tengo la intención de otorgarla a Andy Brown por una respuesta excelente.

Vea los resúmenes debajo de cada cita para una respuesta rápida, y los párrafos para más detalles. También vea la sección de Referencias al final para las fonts autorizadas.

Resúmenes

1. ¿Qué es SimpleMembership / SimpleMembershipProvider (WebMatrix.WebData) y de qué se trata / son responsables?

SimpleMembership (un término que abarca tanto a SimpleMembershipProvider como a SimpleRoleProvider ) es responsable de proporcionar una forma limpia y rápida de implementar un marco de autenticación y autorización Plug and Play al 80% con almacenamiento seguro de contraseñas, que cualquier persona puede usar.

2. ¿Qué es WebSecurity (WebMatrix.WebData)?

WebSecurity es una clase auxiliar para tareas de membresía comunes que funciona junto con Membership y OAuthWebSecurity . Los roles todavía se acceden por separado a través de Roles .

3. ¿Qué es la clase Membership (System.Web.Security)?

Membership es una clase estática de la implementación de membresía ASP.NET original que administra las configuraciones y operaciones del usuario. Muchas operaciones de usuario todavía se realizan aquí en lugar de repetirlas en WebSecurity . Ambos usan el mismo proveedor de su elección.

4.¿Por qué MVC4 crea una tabla UserProfile y una tabla webpages_Membership? ¿Para qué son y cuál es la diferencia? ¿Cuál es la clase UserProfile que crea MVC4?

Las dos tablas realizan diferentes funciones. El esquema de webpages_Membership de webpages_Membership está controlado por el marco y se usa para credenciales, el esquema de UserProfile usuario es controlado por nosotros y se utiliza para cualquier propiedad que deseemos almacenar en un usuario.

5. ¿Qué es la clase UsersContext?

Es un DbContext (parte de la API de DbContext ) proporcionado como un inicio por la plantilla de la aplicación de Internet MVC. Su único trabajo es contener la clase UserProfile para que podamos trabajar con ella (por ejemplo, a través de InitializeSimpleMembershipAttribute ).

6. ¿Cómo funcionan todos estos para hacer la autenticación de usuario?

Esto ahora debería ser evidente a partir de los resúmenes anteriores y el detalle a continuación. Uso: WebSecurity para tareas comunes; UserProfile para propiedades personalizadas para almacenar en contra de un usuario, al que se accede a través de UsersContext (en la plantilla de Visual Studio “MVC Internet Application”); Membership cuando WebSecurity o OAuthWebSecurity no tienen el método; y Roles para roles. Use el controlador de la plantilla VS para ver ejemplos de uso.

Editar . En caso de que alguien llegue tan lejos

Supongamos que tengo una base de datos existente …

Si tiene una base de datos existente y su única razón para escribir un proveedor de membresía personalizado es lidiar con su método de almacenamiento de contraseñas heredado, entonces podría usar una solución alternativa. Esto solo funcionará si puede alejarse de su antiguo almacenamiento de contraseñas al algoritmo SimpleMembership (que usa la clase Rfc2898DeriveBytes ). Ver la nota al pie para más detalles.

Si no puede alejarse, entonces sí tendrá que crear su propio proveedor para usar su algoritmo de contraseña específico, lo cual puede hacer derivando de SimpleMembershipProvider .

NOTA: SimpleMembershipProvider HASH sus contraseñas no las CIFRAR . Si no conoce la diferencia y por qué es importante, piense dos veces antes de hacer su propio proveedor con seguridad personalizada.


Detalle

1.Qué es SimpleMembership / SimpleMembershipProvider

Para comprender cómo encaja todo esto, ayuda a comprender la historia.

  • ASP.NET en 2005 introdujo el sistema de membresía ASP.NET
  • Este sistema utiliza proveedores para abstraer detalles de implementación de interfaces comunes utilizadas para administrar cuentas y roles, etc.
  • También nos dio una capacidad básica de “perfil de usuario” (almacenada en un campo xml de columna única que las personas tendían a evitar)
  • SimpleMembership se lanzó al mundo en 2010 como un proveedor que se conecta al sistema de membresía de ASP.NET, pero también permite la autenticación OAuth y el almacenamiento de perfil de usuario de propiedad por columna (en lugar del almacenamiento de columna única utilizado en el original implementación).
  • SimpleMembershipProvider implementa ExtendedMembershipProvider para ampliar la implementación del proveedor original

Es código abierto en codeplex (reflejado en github ). En lo que respecta a la seguridad, por lo tanto, puede evaluar el código usted mismo, clonarlo, cambiarlo, etc. Debe tener su propia opinión sobre los beneficios y desventajas de la seguridad de código abierto , y cocinar con una pizca de NIH . ( Vista personal: la uso a veces, no la uso otras veces )

ExtendedMembershipProvider en sí mismo agrega comandos como GeneratePasswordResetToken a las antiguas API del proveedor de membresía.

2. ¿Qué es WebSecurity (WebMatrix.WebData)?

WebSecurity es simplemente una fachada, o clase de ayuda, para proporcionar un acceso simple a SimpleMembershipProvider y hacer tareas comunes fáciles y accesibles en un solo lugar. Está ahí para ayudar y porque la extensión del framework original a través de ExtendedMembershipProvider significa que algunas de las clases originales como Membership no son suficientes ahora. Ejemplos:

  • WebSecurity.CurrentUserName – obtiene el nombre del usuario actualmente conectado
  • WebSecurity.CreateUserAndAccount . Simultáneamente cree un usuario y establezca las propiedades del perfil del usuario (por ejemplo, WebSecurity.CreateUserAndAccount(userName, pw, new { Email = model.Email });
  • WebSecurity.InitializeDatabaseConnection : configure rápidamente una base de datos nueva / existente para usar con la membresía, elija su columna de identificación de usuario y el identificador de clave natural del usuario, etc.
  • ResetPassword para restablecer una contraseña de usuario, GeneratePasswordResetToken y muchos más

En general, estos métodos difieren del proveedor que está utilizando , no solo dependen de SimpleMembership, sino que unen objetos como su proveedor y Membership para proporcionar un punto en común para las funciones de membresía.

Tenga en cuenta que también existe OAuthWebSecurity que es el equivalente de WebSecurity para la autenticación OAuth.

3. ¿Qué es la clase Membership (System.Web.Security)?

Membership es de la implementación original; administra la configuración del usuario y realiza operaciones relacionadas con el usuario utilizando la implementación básica MembershipProvider que ExtendedMembershipProvider ahora amplía. Es una clase estática, por lo que está disponible en cualquier lugar donde declare el espacio de nombres, y por lo tanto es una manera fácil de, por ejemplo, recuperar el usuario actual: Membership.GetUser

Existe confusión causada por el hecho de que WebSecurity hace algunas cosas y no otras, y la Membership hace algunas cosas y otras no. Si ve WebSecurity como un juego de herramientas para operaciones de nivel superior, y la Membership como un conjunto de herramientas para hacer cosas a un usuario, estará bien; trabajan juntos en su proveedor.

4.¿Por qué MVC4 crea una tabla UserProfile y una tabla webpages_Membership? ¿Para qué son y cuál es la diferencia? ¿Cuál es la clase UserProfile que crea MVC4?

  • webpages_Membership es una tabla con un esquema fijo que dejamos solos, y permite al proveedor realizar las operaciones básicas de la cuenta, principalmente el almacenamiento de credenciales.
  • UserProfile es una tabla que personalizamos para almacenar información en una cuenta de usuario y la tenemos disponible en un formato fuertemente tipado a través de la clase UserProfile .
  • Hay una tabla adicional llamada webpages_OAuthMembership que hace el mismo trabajo que webpages_Membership , pero para los proveedores de inicio de sesión de OAuth con los que desea integrarse.

La magia de esta configuración es que un solo usuario puede tener un inicio de sesión de membresía en su propio sitio, y cualquier número de inicios de sesión de OAuth con diferentes proveedores como google, facebook y todos ellos comparten un perfil común almacenado en UserProfile

En general, si una tabla comienza con webpages_ , significa que hay una API para acceder a ella. La tabla UserProfile está representada por la clase UserProfile en su UsersContext (si usa la plantilla predeterminada de la aplicación de Internet MVC). Por lo tanto, accedemos a esto a través de los métodos habituales que DbContext con cualquier clase contenida en un DbContext .

UserProfile es muy amigable con el código: puedes agregar columnas (como la dirección de Email del usuario) y luego configurar una migración para incluir esa columna en tu base de datos en tu próxima versión (si te gusta usar migraciones). De hecho, la tabla UserProfile no tiene que llamarse así; puede cambiar eso usando la llamada WebSecurity.InitializeDatabaseConnection , [Table("UserProfile")] public class UserProfile , y sus propias migraciones.

5. ¿Qué es la clase UsersContext?

Esto es de la plantilla de la aplicación MVC Internet proporcionada en Visual Studio New Project. Lo primero que hago es asegurarme de que comparte una cadena de conexión común con mi propio contexto de base de datos (suponiendo que las tablas de membresía estén en la misma base de datos). Puede cambiar esto y desacoplarlo más tarde si lo desea.

No es necesario separarlo en su propio contexto, eso solo es necesario si desea almacenar información de membresía en una base de datos diferente ahora o en el futuro. Si se deshace de ella, puede cambiar las referencias a UsersContext por las suyas. contexto, ajustando Database.SetInitializer .

Referencias

Usando SimpleMembership con ASP.NET WebPages – Matthew Osborn – Esta es la referencia original sobre SimpleMembership y qué es, por qué es y qué hace:

MSDN: introducción a la membresía : la membresía sigue siendo el núcleo de SimpleMembership, por lo que ayuda comprender un poco al respecto.

  • fuente codeplex (reflejada en github ).
  • WebSecurity
  • OAuthWebSecurity
  • SimpleMembershipProvider
  • ExtendedMembershipProvider
  • SimpleRoleProvider
  • Membership
  • Roles
  • DbContext y la API DbContext

EDITAR Nota al pie: el detalle para hacer una actualización progresiva de la contraseña

  • Agregue una propiedad a UserProfile que almacena en qué versión de contraseña está la cuenta (por ejemplo, 1 para el legado, 2 para SimpleMembership)
  • En la acción “Iniciar sesión”, escriba el código de modo que:
    • Si están en su versión de contraseña SimpleMembership, usted hace un inicio de sesión normal
    • Si están en la versión de contraseña heredada, usted:
      • compruébelo usando su viejo método
      • si es correcto lo restablece usando ResetPassword luego ChangePassword para usar la versión de SimpleMembership, esto actualizará el campo a la nueva versión de contraseña
      • y finalmente actualiza la versión de la contraseña en el UserProfile
  • Actualice cualquier otro método AccountsController que use la contraseña de forma similar.
  • Vive con la solución hacky y el acoplamiento a las webpages_Membership tabla de webpages_Membership no debe tocarnos, ya que no tienes que escribir un nuevo proveedor personalizado.

Es posible hacer todo esto transaccional con TransactionScope . Lo único desagradable que está pasando es el código adicional en el controlador y el acoplamiento a las webpages_Membership .