Necesito hacer algo bastante simple: en mi aplicación ASP.NET MVC, quiero establecer un IIdentity / IPrincipal personalizado. Lo que sea más fácil / más adecuado. Quiero extender el valor predeterminado para poder llamar a algo como User.Identity.Id
y User.Identity.Role
. Nada especial, solo algunas propiedades adicionales.
He leído toneladas de artículos y preguntas, pero siento que lo estoy haciendo más difícil de lo que realmente es. Pensé que iba a ser fácil. Si un usuario inicia sesión, quiero establecer una identidad personalizada. Entonces pensé, lo implementaré Application_PostAuthenticateRequest
en mi global.asax. Sin embargo, eso se llama en cada solicitud, y no quiero hacer una llamada a la base de datos en cada solicitud que solicitaría todos los datos de la base de datos y colocaría un objeto IPrincipal personalizado. Eso también parece muy innecesario, lento y en el lugar equivocado (haciendo llamadas a la base de datos allí) pero podría estar equivocado. ¿O de dónde más vendrían esos datos?
Así que pensé, cada vez que un usuario inicia sesión, puedo agregar algunas variables necesarias en mi sesión, que agrego a la identidad personalizada en el Application_PostAuthenticateRequest
controlador de eventos. Sin embargo, mi Context.Session
está null
allí, por lo que tampoco es el camino a seguir.
Llevo un día trabajando en esto y siento que me falta algo. Esto no debería ser demasiado difícil de hacer, ¿verdad? También estoy un poco confundido por todas las cosas (semi) relacionadas que vienen con esto. MembershipProvider
, MembershipUser
, RoleProvider
, ProfileProvider
, IPrincipal
, IIdentity
, FormsAuthentication
.... ¿Soy el único que encuentra todo esto muy confuso?
Si alguien pudiera decirme una solución simple, elegante y eficiente para almacenar algunos datos adicionales en una identidad sin toda la confusión adicional ... ¡eso sería genial! Sé que hay preguntas similares sobre SO, pero si la respuesta que necesito está ahí, debo haberla pasado por alto.
MemberShip...
,Principal
,Identity
. ASP.NET debería hacer esto más fácil, simple y como máximo dos enfoques para tratar con la autenticación.Respuestas:
Así es como lo hago.
Decidí usar IPrincipal en lugar de IIdentity porque significa que no tengo que implementar tanto IIdentity como IPrincipal.
Crea la interfaz
CustomPrincipal
CustomPrincipalSerializeModel: para serializar información personalizada en el campo de datos de usuario en el objeto FormsAuthenticationTicket.
Método de inicio de sesión: configuración de una cookie con información personalizada
Global.asax.cs: leyendo la cookie y reemplazando el objeto HttpContext.User, esto se hace anulando PostAuthenticateRequest
Acceso en vistas de maquinilla de afeitar
y en código:
Creo que el código se explica por sí mismo. Si no es así, házmelo saber.
Además, para facilitar aún más el acceso, puede crear un controlador base y anular el objeto Usuario devuelto (HttpContext.User):
y luego, para cada controlador:
que le permitirá acceder a campos personalizados en código como este:
Pero esto no funcionará dentro de las vistas. Para eso necesitaría crear una implementación personalizada de WebViewPage:
Conviértalo en un tipo de página predeterminado en Views / web.config:
y en las vistas, puedes acceder de esta manera:
fuente
Thread.CurrentPrincipal
enApplication_PostAuthenticateRequest
para que funcione, ya que no se basa enHttpContext.Current.User
FormsAuthentication.SignOut();
funciona bien para mí.No puedo hablar directamente para ASP.NET MVC, pero para ASP.NET Web Forms, el truco es crear
FormsAuthenticationTicket
y cifrarlo en una cookie una vez que el usuario se haya autenticado. De esta manera, solo tiene que llamar a la base de datos una vez (o AD o lo que sea que esté utilizando para realizar su autenticación), y cada solicitud posterior se autenticará en función del ticket almacenado en la cookie.Un buen artículo sobre esto:
http://www.ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html(enlace roto)Editar:
Dado que el enlace anterior está roto, recomendaría la solución de LukeP en su respuesta anterior: https://stackoverflow.com/a/10524305 - También sugeriría que la respuesta aceptada se cambie a esa.
Edición 2: Una alternativa para el enlace roto: https://web.archive.org/web/20120422011422/http://ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html
fuente
Cache
como unSession
reemplazo para mantener los datos en el servidor. ¿Alguien puede decirme si este es un enfoque defectuoso?Aquí hay un ejemplo para hacer el trabajo. bool isValid se configura mirando algún almacén de datos (digamos su base de datos de usuario). UserID es solo una ID que estoy manteniendo. Puede agregar información adicional como dirección de correo electrónico a los datos del usuario.
en el asabal golbal agregue el siguiente código para recuperar su información
Cuando vaya a utilizar la información más adelante, puede acceder a su principal personalizado de la siguiente manera.
esto le permitirá acceder a información personalizada del usuario.
fuente
MVC le proporciona el método OnAuthorize que se cuelga de sus clases de controlador. O bien, puede usar un filtro de acción personalizado para realizar la autorización. MVC lo hace bastante fácil de hacer. Publiqué una publicación de blog sobre esto aquí. http://www.bradygaster.com/post/custom-authentication-with-mvc-3.0
fuente
Aquí hay una solución si necesita conectar algunos métodos a @User para usarlos en sus vistas. No hay solución para una personalización seria de la membresía, pero si la pregunta original fuera necesaria solo para las vistas, entonces esto quizás sería suficiente. Lo siguiente se usó para verificar una variable devuelta desde un filtro de autorización, para verificar si algunos enlaces no se presentaban o no (no para ningún tipo de lógica de autorización o concesión de acceso).
Luego, simplemente agregue una referencia en las áreas web.config y llámela como se muestra a continuación en la vista.
fuente
Basado en la respuesta de LukeP , y agregue algunos métodos para configurar
timeout
yrequireSSL
cooperarWeb.config
.Los enlaces de referencias
Códigos modificados de LukeP
1, conjunto
timeout
basado enWeb.Config
. El FormsAuthentication.Timeout obtendrá el valor de tiempo de espera, que se define en web.config. Envolví los siguientes para ser una función, que devuelve unticket
respaldo.2, configure la cookie para que sea segura o no, según la
RequireSSL
configuración.fuente
Muy bien, entonces soy un criptólogo serio arrastrando esta vieja pregunta, pero hay un enfoque mucho más simple para esto, que fue mencionado por @Baserz arriba. Y eso es usar una combinación de métodos de extensión de C # y almacenamiento en caché (NO use sesión).
De hecho, Microsoft ya ha proporcionado varias extensiones de este tipo en el
Microsoft.AspNet.Identity.IdentityExtensions
espacio de nombres. Por ejemplo,GetUserId()
es un método de extensión que devuelve el ID de usuario. También hayGetUserName()
yFindFirstValue()
, que devuelve reclamos basados en IPrincipal.Por lo tanto, solo necesita incluir el espacio de nombres y luego llamar
User.Identity.GetUserName()
para obtener el nombre de los usuarios según lo configurado por ASP.NET Identity.No estoy seguro de si esto se almacena en caché, ya que la identidad ASP.NET anterior no es de código abierto, y no me he molestado en realizar ingeniería inversa. Sin embargo, si no es así, puede escribir su propio método de extensión, que almacenará en caché este resultado durante un período de tiempo específico.
fuente
IsUserAdministrator
oUserEmail
etc.? Estas pensandoHttpRuntime.Cache
?Como una adición al código LukeP para usuarios de formularios web (no MVC) si desea simplificar el acceso en el código detrás de sus páginas, simplemente agregue el siguiente código a una página base y obtenga la página base en todas sus páginas:
Entonces, en su código detrás, simplemente puede acceder a:
Lo que me falta en un escenario de formulario web es cómo obtener el mismo comportamiento en el código que no está vinculado a la página, por ejemplo, en httpmodules, ¿ debería agregar siempre un elenco en cada clase o hay una forma más inteligente de obtener esto?
Gracias por sus respuestas y gracias a LukeP desde que utiliza sus ejemplos como base para mi usuario personalizado (que ahora tiene
User.Roles
,User.Tasks
,User.HasPath(int)
,User.Settings.Timeout
y muchas otras cosas buenas)fuente
Probé la solución sugerida por LukeP y descubrí que no es compatible con el atributo Autorizar. Entonces, lo modifiqué un poco.
Y finalmente en Global.asax.cs
Ahora puedo acceder a los datos en vistas y controladores simplemente llamando
Para cerrar sesión solo llamo
donde está AuthManager
fuente