net - system web httpcontext current session c#
Con respecto a la caducidad deslizante de la autenticaciĆ³n y sesiĆ³n de formularios de ASP.NET (3)
Esto parece ser imposible. Una vez habilitada la caducidad deslizante, siempre se activa. Si hay una forma de acceder a la sesión sin extenderla, no hemos podido encontrarla.
Entonces, ¿cómo abordar este escenario? Se nos ocurrió la siguiente solución alternativa a la propuesta originalmente en la pregunta. Este es en realidad más eficiente porque no usa un servicio web para llamar a casa cada x segundos.
Así que queremos tener una forma de saber cuándo ha expirado la autenticación de formularios de ASP.NET o la sesión, para que podamos cerrar la sesión de forma proactiva del usuario. Un simple temporizador de JavaScript en cada página ( según lo propuesto por Khalid Abuhakmeh) no sería suficiente porque el usuario podría estar trabajando con la aplicación en múltiples ventanas / pestañas del navegador al mismo tiempo.
La primera decisión que tomamos para simplificar este problema es hacer que el tiempo de vencimiento de la sesión sea unos minutos más largo que el tiempo de vencimiento de la autenticación de formularios. De esta manera, la sesión nunca caducará antes de la autenticación de formularios. Si hay una sesión anterior prolongada la próxima vez que el usuario intente iniciar sesión, la abandonaremos para forzar una nueva sesión.
De acuerdo, ahora solo tenemos que tener en cuenta la caducidad de la autenticación de formularios.
A continuación, decidimos deshabilitar la caducidad automática de deslizamiento de la autenticación de formularios (según lo establecido en web.config) y crear nuestra propia versión.
public static void RenewAuthenticationTicket(HttpContext currentContext)
{
var authenticationTicketCookie = currentContext.Request.Cookies["AuthTicketNameHere"];
var oldAuthTicket = FormsAuthentication.Decrypt(authenticationTicketCookie.Value);
var newAuthTicket = oldAuthTicket;
newAuthTicket = FormsAuthentication.RenewTicketIfOld(oldAuthTicket); //This triggers the regular sliding expiration functionality.
if (newAuthTicket != oldAuthTicket)
{
//Add the renewed authentication ticket cookie to the response.
authenticationTicketCookie.Value = FormsAuthentication.Encrypt(newAuthTicket);
authenticationTicketCookie.Domain = FormsAuthentication.CookieDomain;
authenticationTicketCookie.Path = FormsAuthentication.FormsCookiePath;
authenticationTicketCookie.HttpOnly = true;
authenticationTicketCookie.Secure = FormsAuthentication.RequireSSL;
currentContext.Response.Cookies.Add(authenticationTicketCookie);
//Here we have the opportunity to do some extra stuff.
SetAuthenticationExpirationTicket(currentContext);
}
}
Llamamos a este método desde el evento OnPreRenderComplete
en la clase BasePage de nuestra aplicación, de la cual se heredan todas las demás páginas. Hace exactamente lo mismo que la funcionalidad de expiración deslizante normal, pero tenemos la oportunidad de hacer algunas cosas adicionales; Como llamar a nuestro método SetAuthenticationExpirationTicket
.
public static void SetAuthenticationExpirationTicket(HttpContext currentContext)
{
//Take the current time, in UTC, and add the forms authentication timeout (plus one second for some elbow room ;-)
var expirationDateTimeInUtc = DateTime.UtcNow.AddMinutes(FormsAuthentication.Timeout.TotalMinutes).AddSeconds(1);
var authenticationExpirationTicketCookie = new HttpCookie("AuthenticationExpirationTicket");
//The value of the cookie will be the expiration date formatted as milliseconds since 01.01.1970.
authenticationExpirationTicketCookie.Value = expirationDateTimeInUtc.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds.ToString("F0");
authenticationExpirationTicketCookie.HttpOnly = false; //This is important, otherwise we cannot retrieve this cookie in javascript.
authenticationExpirationTicketCookie.Secure = FormsAuthentication.RequireSSL;
currentContext.Response.Cookies.Add(authenticationExpirationTicketCookie);
}
Ahora tenemos una cookie adicional a nuestra disposición que siempre representa el tiempo correcto de caducidad de autenticación de formularios, incluso si el usuario trabaja en diferentes ventanas / pestañas del navegador. Después de todo, las cookies tienen un amplio alcance de navegador. Ahora lo único que queda es una función javascript para verificar el valor de la cookie.
function CheckAuthenticationExpiration() {
var c = $.cookie("AuthenticationExpirationTicket");
if (c != null && c != "" && !isNaN(c)) {
var now = new Date();
var ms = parseInt(c, 10);
var expiration = new Date().setTime(ms);
if (now > expiration) location.reload(true);
}
}
(Tenga en cuenta que usamos el complemento de cookies de jQuery para recuperar la cookie).
Ponga esta función en un intervalo, y los usuarios se desconectarán en el momento en que caduque la autenticación de sus formularios. Voilà :-) Un beneficio adicional de esta implementación es que ahora tiene control sobre cuándo se extiende la caducidad de la autenticación de formularios. Si desea un grupo de servicios web que no extiendan la caducidad, simplemente no llame al método RenewAuthenticationTicket
para ellos.
Por favor, deje un comentario si tiene algo que añadir!
Tenemos una aplicación ASP.NET 4.5 WebForms que utiliza la autenticación de formularios nativos y la funcionalidad de sesión. Ambos tienen un tiempo de espera de 20 minutos con vencimiento deslizante.
Imagina el siguiente escenario. Un usuario ha trabajado en nuestra aplicación por un tiempo y luego procede a hacer otras cosas, dejando nuestra aplicación inactiva durante 20 minutos. El usuario vuelve a nuestra aplicación para escribir un informe. Sin embargo, cuando el usuario intenta guardar, se le trata con la pantalla de inicio de sesión y se pierde el informe.
Obviamente, esto no es deseado. En lugar de este escenario, queremos que el navegador sea redirigido a la página de inicio de sesión en el momento en que la autenticación o la sesión haya caducado. Para darnos cuenta de esto, hemos creado un servicio Web Api al que se puede llamar para verificar si este es el caso.
public class SessionIsActiveController : ApiController
{
/// <summary>
/// Gets a value defining whether the session that belongs with the current HTTP request is still active or not.
/// </summary>
/// <returns>True if the session, that belongs with the current HTTP request, is still active; false, otherwise./returns>
public bool GetSessionIsActive()
{
CookieHeaderValue cookies = Request.Headers.GetCookies().FirstOrDefault();
if (cookies != null && cookies["authTicket"] != null && !string.IsNullOrEmpty(cookies["authTicket"].Value) && cookies["sessionId"] != null && !string.IsNullOrEmpty(cookies["sessionId"].Value))
{
var authenticationTicket = FormsAuthentication.Decrypt(cookies["authTicket"].Value);
if (authenticationTicket.Expired) return false;
using (var asdc = new ASPStateDataContext()) // LINQ2SQL connection to the database where our session objects are stored
{
var expirationDate = SessionManager.FetchSessionExpirationDate(cookies["sessionId"].Value + ApplicationIdInHex, asdc);
if (expirationDate == null || DateTime.Now.ToUniversalTime() > expirationDate.Value) return false;
}
return true;
}
return false;
}
}
El cliente llama a este servicio Web Api cada 10 segundos para verificar si la autenticación o la sesión han caducado. Si es así, el script redirige el navegador a la página de inicio de sesión. Esto funciona como un encanto.
Sin embargo, al llamar a este servicio se activa la caducidad deslizante tanto de la autenticación como de la sesión. Por lo tanto, esencialmente, creando la autenticación y la sesión sin fin. He establecido un punto de interrupción al inicio del servicio para verificar si es una de nuestras funciones las que lo activan. Pero este no es el caso, parece ocurrir en algún lugar más profundo en ASP.NET, antes de la ejecución del servicio.
- ¿Hay alguna manera de deshabilitar la activación de la autenticación de ASP.NET y el vencimiento de la sesión para una solicitud específica?
- Si no, ¿cuál es la mejor práctica para enfrentar un escenario como este?
La funcionalidad de su sitio web debería funcionar sin JavaScript o simplemente reemplaza un problema por otro. También he abordado este problema y aquí es cómo se resolvió:
Cuando se autentica, la cookie de sesión se crea con la duración predeterminada en 20 min. Cuando este caduque el usuario se desconectará.
Cuando el usuario selecciona "recordarme" en el formulario de inicio de sesión, se crea una cookie de persistencia adicional [AuthCookie] en el lado del cliente y en la base de datos. Esta cookie tiene una duración de 1 mes. Cada vez que se carga una página, los datos de la cookie de sesión y persistencia se recrean con una nueva vida útil (normalmente, se desea descifrar / cifrar el ticket).
Imagina el siguiente escenario. Un usuario ha trabajado en nuestra aplicación por un tiempo y luego procede a hacer otras cosas, dejando nuestra aplicación inactiva durante 20 minutos. El usuario vuelve a nuestra aplicación para escribir un informe. Cuando el usuario intenta guardar, su sesión se restaura antes de la solicitud.
Una forma de hacer esto es extender global.aspx para manejar la solicitud previa. Algo en las líneas de:
void application_PreRequestHandlerExecute(object sender, EventArgs e){
...
if (HttpContext.Current.Handler is IRequiresSessionState) {
if (!context.User.Identity.IsAuthenticated)
AuthService.DefaultProvider.AuthenticateUserFromExternalSource();
AuthenticateUserFromExternalSource debe verificar si los datos de las cookies coinciden con los de la base de datos, ya que cualquier cosa almacenada en el lado del cliente puede modificarse. Si tiene servicios de pago con derechos de acceso, debe verificar si el usuario todavía tiene esos derechos y luego puede recrear la sesión.
Todo esto se puede resolver desde el lado del cliente, sin la necesidad de volver al servidor.
En JavaScript hacer esto.
var timeout = setTimeout(function () {
window.location = "/login";
}, twentyMinutesInMilliseconds + 1);
El tiempo de espera se establecerá en 20 minutos en cada actualización de la página. Esto asegura que el usuario necesita realizar todo su trabajo antes de que se agote el tiempo de espera. Muchos sitios utilizan este método y le ahorra realizar solicitudes de servidor innecesarias.