Emparelhando O Estado Da Sessão ASP.NET Com Autenticação Por Formulário
Hoje, estava a falar com o João acerca de um modo de emparelhar a duração da estado de sessão ASP.NET com a duração do ticket de autenticação por formulário.
A minha ideia era guardar o identificador de sessão na propriedade UserData forms authentication ticket durante o login e obtê-lo através de um session ID manager desenvolvido para o efeito.
O código do login seria algo assim:
protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
{
bool isPersistent = this.Login1.RememberMeSet;
string username = this.Login1.UserName;
var ticket = new FormsAuthenticationTicket(
0,
username,
DateTime.Now,
DateTime.Now.AddMinutes(2),
isPersistent,
Guid.NewGuid().ToString("N"));
// Encrypt the ticket.
var encryptedTicket = FormsAuthentication.Encrypt(ticket);
// Create the cookie.
this.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket));
// Redirect back to original URL.
this.Response.Redirect(FormsAuthentication.GetRedirectUrl(username, isPersistent));
}
Para efeitos de demonstração estou a usar um Guid como identificador de sessão.
O session ID manager vai retornar ao session state HTTP module o identificador de sessão uando este o pedir:
public class SessionIdManager : global::System.Web.SessionState.ISessionIDManager
{
#region ISessionIDManager Members
public string CreateSessionID(HttpContext context)
{
return GetDummySessionIdOrRedirectToLoginPage(context);
}
public string GetSessionID(HttpContext context)
{
return GetSessionIdFromFormsIdentity(context);
}
public void Initialize()
{
}
public bool InitializeRequest(HttpContext context, bool suppressAutoDetectRedirect, out bool supportSessionIDReissue)
{
supportSessionIDReissue = false;
return GetSessionIdFromFormsIdentity(context) == null;
}
public void RemoveSessionID(HttpContext context)
{
}
public void SaveSessionID(HttpContext context, string id, out bool redirected, out bool cookieAdded)
{
redirected = false;
cookieAdded = false;
}
public bool Validate(string id)
{
return true;
}
#endregion
private static string GetSessionIdFromFormsIdentity(HttpContext context)
{
var identity = context.User != null ? context.User.Identity as FormsIdentity : null;
if ((identity == null) || (identity.Ticket == null) || string.IsNullOrEmpty(identity.Ticket.UserData))
{
return GetDummySessionIdOrRedirectToLoginPage(context);
}
else
{
return identity.Ticket.UserData;
}
}
private static string GetDummySessionIdOrRedirectToLoginPage(HttpContext context)
{
if (context.Request.CurrentExecutionFilePath.Equals(FormsAuthentication.DefaultUrl, StringComparison.OrdinalIgnoreCase)
|| context.Request.CurrentExecutionFilePath.Equals(FormsAuthentication.LoginUrl, StringComparison.OrdinalIgnoreCase))
{
return Guid.NewGuid().ToString("N");
}
else
{
FormsAuthentication.RedirectToLoginPage();
return null;
}
}
}
NOTA: Embora este código deva funcionar, trata-se apenas de um exercício intelectual e não foi devidamente testado.