Tengo un problema extraño con el uso de la autenticación de cookies Owin.
Cuando inicio mi autenticación del servidor IIS funciona perfectamente bien en IE / Firefox y Chrome.
Comencé a hacer algunas pruebas con autenticación e iniciar sesión en diferentes plataformas y se me ocurrió un error extraño. Esporádicamente, el framework Owin / IIS simplemente no envía ninguna cookie a los navegadores. Escribiré un nombre de usuario y una contraseña que es correcta, el código se ejecuta pero no se envía ninguna cookie al navegador. Si reinicio el servidor, comienza a funcionar, en algún momento intentaré iniciar sesión y nuevamente las cookies dejarán de entregarse. Pasar por encima del código no hace nada y no arroja errores.
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
CookieHttpOnly = true,
AuthenticationType = "ABC",
LoginPath = new PathString("/Account/Login"),
CookiePath = "/",
CookieName = "ABC",
Provider = new CookieAuthenticationProvider
{
OnApplyRedirect = ctx =>
{
if (!IsAjaxRequest(ctx.Request))
{
ctx.Response.Redirect(ctx.RedirectUri);
}
}
}
});
Y dentro de mi procedimiento de inicio de sesión tengo el siguiente código:
IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
authenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var authentication = HttpContext.Current.GetOwinContext().Authentication;
var identity = new ClaimsIdentity("ABC");
identity.AddClaim(new Claim(ClaimTypes.Name, user.Username));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.User_ID.ToString()));
identity.AddClaim(new Claim(ClaimTypes.Role, role.myRole.ToString()));
authentication.AuthenticationResponseGrant =
new AuthenticationResponseGrant(identity, new AuthenticationProperties()
{
IsPersistent = isPersistent
});
authenticationManager.SignIn(new AuthenticationProperties() {IsPersistent = isPersistent}, identity);
Actualización 1: Parece que una de las causas del problema es que cuando agrego elementos a la sesión comienzan los problemas. Agregar algo simple como Session.Content["ABC"]= 123
parece crear el problema.
Lo que puedo ver es lo siguiente: 1) (Chrome) Cuando inicio sesión, obtengo ASP.NET_SessionId + mi cookie de autenticación. 2) Voy a una página que establece una sesión. Contenido ... 3) Abra un nuevo navegador (Firefox) e intente iniciar sesión y no recibe un ASP.NET_SessionId ni recibe una Cookie de autenticación 4) Mientras que el primer navegador tiene ASP.NET_SessionId y continúa funcionando. En el momento en que elimino esta cookie, tiene el mismo problema que todos los demás navegadores en los que estoy trabajando en la dirección IP (10.xxx) y localhost.
Actualización 2: Forzar la creación de ASPNET_SessionId
primero en mi página login_load antes de la autenticación con OWIN.
1) antes de autenticarme con OWIN hago un Session.Content
valor aleatorio en mi página de inicio de sesión para iniciar ASP.NET_SessionId 2) luego me autentico y realizo más sesiones 3) Parece que ahora otros navegadores funcionan
Esto es extraño Solo puedo concluir que esto tiene algo que ver con ASP y OWIN pensando que están en diferentes dominios o algo así.
Actualización 3 - Comportamiento extraño entre los dos.
Comportamiento extraño adicional identificado: el tiempo de espera de Owin y la sesión ASP es diferente. Lo que estoy viendo es que mis sesiones Owin se mantienen vivas más tiempo que mis sesiones ASP a través de algún mecanismo. Entonces, al iniciar sesión: 1.) Tengo una sesión de autenticación basada en cocina 2.) Establezco algunas variables de sesión
Mis variables de sesión (2) "mueren" antes de que la variable de sesión de cookie owin fuerce el reinicio de sesión, lo que provoca un comportamiento inesperado en toda mi aplicación. (La persona ha iniciado sesión pero realmente no ha iniciado sesión)
Actualización 3B
Después de investigar un poco, vi algunos comentarios en una página que dicen que el tiempo de espera de autenticación de "formularios" y el tiempo de espera de la sesión deben coincidir. Estoy pensando que normalmente los dos están sincronizados, pero por alguna razón los dos no están sincronizados.
Resumen de soluciones alternativas
1) Siempre cree una sesión primero antes de la autenticación. Básicamente crea una sesión cuando inicias la aplicaciónSession["Workaround"] = 0;
2) [Experimental] si persiste las cookies, asegúrese de que su tiempo de espera / duración OWIN sea más largo que su sesión Tiempo de espera en su web.config (en prueba)
fuente
Respuestas:
Encontré el mismo problema y rastreé la causa de la implementación del alojamiento OWIN ASP.NET. Yo diría que es un error.
Algunos antecedentes
Mis hallazgos se basan en estas versiones de ensamblaje:
OWIN utiliza su propia abstracción para trabajar con Cookies de respuesta ( Microsoft.Owin.ResponseCookieCollection ). Esta implementación envuelve directamente la colección de encabezados de respuesta y, en consecuencia, actualiza el encabezado Set-Cookie . El host OWIN ASP.NET ( Microsoft.Owin.Host.SystemWeb ) simplemente envuelve System.Web.HttpResponse y es la colección de encabezados. Entonces, cuando se crea una nueva cookie a través de OWIN, el encabezado Set-Cookie de respuesta se cambia directamente.
Pero ASP.NET también usa su propia abstracción para trabajar con cookies de respuesta. Esto se expone a nosotros como propiedad System.Web.HttpResponse.Cookies e implementado por la clase sellada System.Web.HttpCookieCollection . Esta implementación no ajusta el encabezado Set-Cookie de la respuesta directamente, pero utiliza algunas optimizaciones y un puñado de notificaciones internas para manifestar su estado cambiado al objeto de respuesta.
Luego, hay un punto tardío en la vida útil de la solicitud en el que se prueba el estado cambiado de HttpCookieCollection ( System.Web.HttpResponse.GenerateResponseHeadersForCookies () ) y las cookies se serializan en el encabezado Set-Cookie . Si esta colección se encuentra en un estado específico, el encabezado Set-Cookie completo se borra primero y se recrea de las cookies almacenadas en la colección.
La implementación de la sesión ASP.NET usa la propiedad System.Web.HttpResponse.Cookies para almacenar su cookie ASP.NET_SessionId. También hay una optimización básica en el módulo de estado de sesión ASP.NET ( System.Web.SessionState.SessionStateModule ) implementado a través de la propiedad estática llamada s_sessionEverSet, que se explica por sí mismo. Si alguna vez almacena algo en el estado de sesión en su aplicación, este módulo hará un poco más de trabajo para cada solicitud.
Volver a nuestro problema de inicio de sesión
Con todas estas piezas se pueden explicar sus escenarios.
Caso 1 - La sesión nunca se configuró
System.Web.SessionState.SessionStateModule , la propiedad s_sessionEverSet es falsa. El módulo de estado de sesión no genera identificaciones de sesión y el estado de la colección System.Web.HttpResponse.Cookies no se detecta como modificado . En este caso, las cookies OWIN se envían correctamente al navegador y el inicio de sesión funciona.
Caso 2: la sesión se usó en algún lugar de la aplicación, pero no antes de que el usuario intente autenticarse
System.Web.SessionState.SessionStateModule , la propiedad s_sessionEverSet es verdadera. Los Id. De sesión son generados por SessionStateModule , ASP.NET_SessionId se agrega a la colección System.Web.HttpResponse.Cookies pero se elimina más adelante en la vida útil de la solicitud ya que la sesión del usuario está de hecho vacía. En este caso , el estado de la colección System.Web.HttpResponse.Cookies se detecta como modificado y el encabezado Set-Cookie se borra primero antes de que las cookies se serialicen al valor del encabezado.
En este caso, las cookies de respuesta OWIN se "pierden" y el usuario no se autentica y se redirige a la página de inicio de sesión.
Caso 3: la sesión se usa antes de que el usuario intente autenticarse
System.Web.SessionState.SessionStateModule , la propiedad s_sessionEverSet es verdadera. Los Id. De sesión son generados por SessionStateModule , ASP.NET_SessionId se agrega a System.Web.HttpResponse.Cookies . Debido a la optimización interna en System.Web.HttpCookieCollection y System.Web.HttpResponse.GenerateResponseHeadersForCookies () el encabezado Set-Cookie NO se borra primero, sino que solo se actualiza.
En este caso, las cookies de autenticación OWIN y la cookie ASP.NET_SessionId se envían en respuesta y el inicio de sesión funciona.
Problema más general con las cookies.
Como puede ver, el problema es más general y no se limita a la sesión ASP.NET. Si está alojando OWIN a través de Microsoft.Owin.Host.SystemWeb y usted / algo está utilizando directamente la colección System.Web.HttpResponse.Cookies , está en riesgo.
Por ejemplo, esto funciona y ambas cookies se envían correctamente al navegador ...
Pero esto no es así y OwinCookie está "perdido" ...
Ambos probados desde VS2013, IISExpress y la plantilla de proyecto MVC predeterminada.
fuente
Comenzando con el gran análisis de @TomasDolezal, eché un vistazo a la fuente Owin y System.Web.
El problema es que System.Web tiene su propia fuente maestra de información de cookies y ese no es el encabezado Set-Cookie. Owin solo sabe sobre el encabezado Set-Cookie. Una solución alternativa es asegurarse de que las cookies establecidas por Owin también se establezcan en la
HttpContext.Current.Response.Cookies
colección.He hecho un pequeño middleware ( fuente , nuget ) que hace exactamente eso, que está destinado a colocarse inmediatamente encima del registro de middleware de cookies.
fuente
app.UseKentorCookieMiddlewareSaver();
en Startup.Auth.cs. También debe manejar la eliminación de cookies de cierre de sesión.app.UseKentorOwinCookieSaver()
y tal vez incluido en su respuesta original como en la página GitHub del paquete .En resumen, el administrador de cookies .NET se ganará al administrador de cookies OWIN y sobrescribirá las cookies establecidas en la capa OWIN . La solución es usar la clase SystemWebCookieManager, que se proporciona como solución en el Proyecto Katana aquí . Debe usar esta clase o una similar, lo que obligará a OWIN a usar el administrador de cookies .NET para que no haya inconsistencias :
En el inicio de su aplicación, simplemente asígnela cuando cree sus dependencias OWIN:
Aquí se ha proporcionado una respuesta similar, pero no incluye toda la base de código requerida para resolver el problema, por lo que veo la necesidad de agregarla aquí porque el enlace externo al Proyecto Katana puede fallar y esto debería estar completamente documentado como solución aquí también.
fuente
ASP.NET Webforms, OWIN, ADFS
Startup.ConfigureAuth
que tenemosapp.UseCookieAuthentication
yapp.UseWsFederationAuthentication
finalmenteapp.UseStageMarker
El equipo de Katana respondió al problema que Tomas Dolezar planteó y publicó documentación sobre soluciones alternativas :
Consulte la implementación de SystemWebCookieManager en la documentación (enlace anterior)
Más información aquí.
Editar
Debajo de los pasos que tomamos para resolver el problema. Tanto 1. como 2. resolvieron el problema también por separado, pero decidimos aplicar ambos por si acaso:
1. Utilice SystemWebCookieManager
2. Establezca la variable de sesión:
(nota al margen: el método de inicialización anterior es el lugar lógico para la corrección porque base. a la aplicación. Los problemas ocurrirían después de la redirección a la aplicación, mientras que la corrección establece la variable de sesión ya durante la primera solicitud anónima, solucionando así el problema antes de que ocurra cualquier redirección)
Editar 2
Copiar y pegar del proyecto Katana 14/05/2016:
Agrega esto:
...y esto:
fuente
ControllerContext.HttpContext.Session.RemoveAll();
en tuExternalLogin()
acción, antes de llamarChallengeResult()
. No sé si es la mejor solución, pero es la más simple.?.
(operador condicional nulo) solo funciona en C # 6.Ya se han proporcionado respuestas, pero en owin 3.1.0, hay una clase SystemWebChunkingCookieManager que se puede usar.
https://github.com/aspnet/AspNetKatana/blob/dev/src/Microsoft.Owin.Host.SystemWeb/SystemWebChunkingCookieManager.cs
https://raw.githubusercontent.com/aspnet/AspNetKatana/c33569969e79afd9fb4ec2d6bdff877e376821b2/src/Microsoft.Owin.Host.SystemWeb/SystemWebChunkingCookieManager.cs
fuente
Si usted mismo está configurando cookies en el middleware OWIN, el uso
OnSendingHeaders
parece solucionar el problema.Por ejemplo, se establecerá el uso del siguiente código
owinResponseCookie2
, aunqueowinResponseCookie1
no sea así:fuente
Me enfrenté al problema similar con Visual Studio 2017 y .net MVC 5.2.4 , ¡Actualizar Nuget Microsoft.Owin.Security.Google a la última versión que actualmente es 4.0.1 funcionó para mí! ¡Espero que esto ayude a alguien!
fuente
La solución de código de una línea más rápida:
Simplemente agregue esta línea antes del método CreateIdentity:
fuente
HttpContext.Current.Session["RunSession"] = "1";
? en Globa.asaxSession_Start
?Tuve el mismo síntoma de que el encabezado Set-Cookie no se envió, pero ninguna de estas respuestas me ayudó. Todo funcionaba en mi máquina local, pero cuando se implementaba en producción, los encabezados set-cookie nunca se configuraban.
Resulta que fue una combinación de usar una costumbre
CookieAuthenticationMiddleware
con WebApi junto con el soporte de compresión WebApiAfortunadamente, estaba usando ELMAH en mi proyecto, lo que me permitió registrar esta excepción:
Lo que me llevó a este problema de GitHub
Básicamente, si tiene una configuración extraña como la mía, querrá deshabilitar la compresión de sus controladores / métodos de WebApi que configuran cookies, o pruebe el
OwinServerCompressionHandler
.fuente