2010-02-10 3 views
4

Каков наилучший способ показать сообщение пользователю после окончания сессии? К тому времени пользователь должен быть выведен из системы и перенаправлен на стартовую страницу. Я могу использовать javascript для перенаправления пользователя на стартовую страницу. Я просто хочу показать сообщение на стартовой странице.Уведомлять пользователя, когда время сеанса в asp.net

ответ

1

В вашей переадресации JavaScript добавьте параметр querystring к URL-адресу переадресации.

<script> 
... 
// If session is about to timeout... 
location.href = '/home.aspx?action=expired'; 
... 
</script> 

Затем в начальной странице, вы можете иметь код для проверки строки запроса и отображать сообщение, если это так.

<% 
'home.aspx 
If Request.QueryString("action") = "expired" Then 
    Response.Write("<p>You have been logged out due to inactivity.</p>") 
End If 
%> 
+3

Response.Write! Aaaaaaaahh !!! :) – markt

+0

видa вонючий, Shawn. ; -p Механизм является искусственным и каким-то образом должен применяться на каждой конечной точке. И .. как вы узнаете «Если сеанс близок к тайм-ауту ...» на клиенте? [вставьте здесь много ответов]. Хорошо, но что, если пользователь обращается к другой странице сайта на другой вкладке или на странице, делает запрос Ajax удачным сеансом? Не помешивая, просто скажи ... –

+0

О, я слышу тебя ... Но однажды он сказал в комментарии (кажется, сейчас уже нет), что у него уже был тайм-аут сеанса, и он просто хотел отобразить сообщение на начальную страницу, к которой он перенаправляет. Поэтому я предположил, что у него есть location.href где-то установлен, и просто показывал ему, как изменить эту часть, чтобы отобразить сообщение на стартовой странице. –

2

Обычно страница будет использовать JavaScript для хранения таймера и отображения всплывающего окна или сообщения dhtml минут или двух до сеанс истекает. Мой банк делает это.

Это очень раздражает, потому что, если у пользователя есть несколько вкладок, открытых для одного и того же сайта, одна вкладка будет знать, что сессия истечет, но другая вкладка не будет, поэтому вы можете получить предупреждение, даже если оно не правда. Если вы попытаетесь использовать вызов AJAX для запроса сервера на время до истечения срока действия сеанса, вы просто увеличили время ожидания сеанса и фактически сделали сеанс никогда не истекающим, пока открыто окно браузера (что может быть не так уж плохо в зависимости от вашей конкретной ситуации).

+0

Эй, сам .. шип, который я нокаутировал прошлой ночью, решает все эти проблемы и обеспечивает ссылочную реализацию как для состояния сеанса, так и для форм auth. может быть, какой-то банк должен нанять меня ... ;-) –

+1

@Sky, я уверен, что вы переоценены для моего банка. Они, по-видимому, только нанимают идиотов. –

15

Предыдущая версия этого ответа содержит простой источник для решения вопроса, который больше не существует.

Сценарий был, что он хотел быть уведомлен перед тем сеанса истекло, так что могут быть приняты меры.

Неясно, было ли это сеансом asp.net или билетом проверки подлинности форм, но на самом деле это та же проблема.

В основном это управление состоянием сеанса асинхронного сеанса без запуска обновления сеанса/билета. Общее желание для приложений ajax.

Решение довольно простое, но не совсем прямое. Есть немало проблем для решения, но я разработал решение, которое работает как для простого состояния сеанса, так и для проверки подлинности форм.

Он составлен из очень легкого httpmodule и сопутствующей клиентской библиотеки скриптов, и не более 50 или 60 эффективных строк кода.

Стратегия заключается в предоставлении конечной точки http, которая может запрашивать состояние истечения срока действия сеанса или билета формы, не обновляя их. Модуль просто сидит на передней части конвейера и обслуживает пару «виртуальных» конечных точек с датами javascript и очень простой js lib для совершения вызовов.

Демо и источник здесь: AsynchronousSessionAuditor

Некоторые из вас задаются вопросом, почему я бы иметь дело с этим, но, вероятно, больше из вас говорят ад да, что боль в patoot. Я знаю, что в прошлом я придумал хрупкие вонючие обходные пути, и я очень доволен этим.

Он может служить в стандартном приложении с обратной почтой или, скорее, в приложении ajax. Также ... Вы можете узнать больше о жизненном цикле запроса Http here и here. Если интересно, узнайте больше об использовании raw xmlhttp для конечных точек asp.net here

Сокращение предыдущего кода спайка. проверьте историю изменений, если вы заинтересованы.

Вот соответствующие исходные файлы. Полная ссылочная реализация доступна по ссылке, приведенной выше ....

HttpModule

// <copyright project="AsynchronousSessionAuditor" file="AsynchronousSessionAuditorModule.cs" company="Sky Sanders"> 
// This source is a Public Domain Dedication. 
// http://spikes.codeplex.com 
// Attribution is appreciated. 
// </copyright> 

using System; 
using System.Web; 
using System.Web.Security; 
using System.Web.SessionState; 

namespace Salient.Web.Security 
{ 
    /// <summary> 
    /// AsynchronousSessionAuditorModule provides a mechanism for auditing the lifecycle 
    /// of an ASP.Net session and/or an ASP.Net FormsAuthentication cookie in the interest 
    /// of providing better monitoring and control of a user session. This is becoming more 
    /// important as more and more web apps are single page apps that may not cycle a page for 
    /// many minutes or hours. 
    /// 
    /// Storing a token in the Asp.net Session was for many years the default authentication strategy. 
    /// The are still valid applications for this techique although FormsAuthentication has far 
    /// surpassed in security and functionality. 
    /// 
    /// What I am providing is a manner in which to transparently monitor the expiration status of each 
    /// by implementing a module that recognizes two virtual endpoints: 
    /// 
    /// http://mysite/.aspnetsession 
    /// http://mysite/.formsauthticket 
    /// 
    /// By making a request to these urls you will be delivered a javascript date in numeric form that 
    /// represents the expiration dateTime of either the current ASP.Net session, if any, or the current 
    /// FormsAuthentication ticket expiration, if any. 
    /// 
    /// If the requested item does not exists, zero is returned. Any value served by this module should 
    /// be cast to a date and compared with Now. If less than you should take action. You should have 
    /// taken action on the client before the session timed out, aided by the output of this module, but 
    /// hey, nobody is perfect. 
    /// </summary> 
    public class AsynchronousSessionAuditorModule : IHttpModule 
    { 
     // note: these must remain in sync with the string keys in the javascript 
     private const string AspSessionAuditKey = ".aspnetsession"; 

     private const string FormsAuthAuditKey = ".formsauthticket"; 

     #region IHttpModule Members 

     public void Init(HttpApplication context) 
     { 
      // this is our audit hook. get the request before anyone else does 
      // and if it is for us handle it and end. no one is the wiser. 
      // otherwise just let it pass... 
      context.BeginRequest += HandleAuditRequest; 

      // this is as early as we can access session. 
      // it is also the latest we can get in, as the script handler is coming 
      // right after and we want to beat the script handler to the request 
      // will have to set a cookie for the next audit request to read in Begin request. 
      // the cookie is used nowhere else. 
      context.PostAcquireRequestState += SetAuditBugs; 
     } 

     public void Dispose() 
     { 
     } 

     #endregion 

     private static void SetAuditBugs(object sender, EventArgs e) 
     { 
      HttpApplication app = (HttpApplication) sender; 

      if ((app.Context.Handler is IRequiresSessionState || app.Context.Handler is IReadOnlySessionState)) 
      { 
       HttpCookie sessionTimeoutCookie = new HttpCookie(AspSessionAuditKey); 

       // check to see if there is a session cookie 
       string cookieHeader = app.Context.Request.Headers["Cookie"]; 
       if ((null != cookieHeader) && (cookieHeader.IndexOf("ASP.NET_SessionId") >= 0) && 
        !app.Context.Session.IsNewSession) 
       { 
        // session is live and this is a request so lets ensure the life span 
        app.Context.Session["__________SessionKicker"] = DateTime.Now; 
        sessionTimeoutCookie.Expires = DateTime.Now.AddMinutes(app.Session.Timeout).AddSeconds(2); 
        sessionTimeoutCookie.Value = MilliTimeStamp(sessionTimeoutCookie.Expires).ToString(); 
       } 
       else 
       { 
        // session has timed out; don't fiddle with it 
        sessionTimeoutCookie.Expires = DateTime.Now.AddDays(-30); 
        sessionTimeoutCookie.Value = 0.ToString(); 
       } 
       app.Response.Cookies.Add(sessionTimeoutCookie); 
      } 
     } 

     private static void HandleAuditRequest(object sender, EventArgs e) 
     { 
      HttpContext context = ((HttpApplication) sender).Context; 
      bool formsAudit = context.Request.Url.PathAndQuery.ToLower().StartsWith("/" + FormsAuthAuditKey); 
      bool aspSessionAudit = context.Request.Url.PathAndQuery.ToLower().StartsWith("/" + AspSessionAuditKey); 

      if (!formsAudit && !aspSessionAudit) 
      { 
       // your are not the droids i am looking for, you may move along... 
       return; 
      } 

      double timeout; 
      // want to know forms auth status 
      if (formsAudit) 
      { 
       HttpCookie formsAuthCookie = context.Request.Cookies[FormsAuthentication.FormsCookieName]; 
       if (formsAuthCookie != null) 
       { 
        FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(formsAuthCookie.Value); 
        timeout = MilliTimeStamp(ticket.Expiration); 
       } 
       else 
       { 
        timeout = 0; 
       } 
      } 
       // want to know session status 
      else 
      { 
       // no session here, just take the word of SetAuditBugs 
       HttpCookie sessionTimeoutCookie = context.Request.Cookies[AspSessionAuditKey]; 
       timeout = sessionTimeoutCookie == null ? 0 : Convert.ToDouble(sessionTimeoutCookie.Value); 
      } 

      // ensure that the response is not cached. That would defeat the whole purpose 
      context.Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1)); 
      context.Response.Cache.SetCacheability(HttpCacheability.NoCache); 
      context.Response.Cache.SetNoStore(); 
      // the money shot. a javascript date. 
      context.Response.Write(timeout.ToString()); 
      context.Response.Flush(); 
      context.Response.End(); 
     } 

     /// <summary> 
     /// Found Code: http://forums.asp.net/t/1044408.aspx 
     /// </summary> 
     /// <param name="TheDate"></param> 
     /// <returns></returns> 
     private static double MilliTimeStamp(DateTime TheDate) 
     { 
      DateTime d1 = new DateTime(1970, 1, 1); 
      DateTime d2 = TheDate.ToUniversalTime(); 
      TimeSpan ts = new TimeSpan(d2.Ticks - d1.Ticks); 

      return ts.TotalMilliseconds; 
     } 
    } 
} 

Клиентская библиотека

// <copyright project="AsynchronousSessionAuditor" file="AsynchronousSessionAuditor.js" company="Sky Sanders"> 
// This source is a Public Domain Dedication. 
// http://spikes.codeplex.com 
// Attribution is appreciated. 
// </copyright> 


var AsynchronousSessionAuditor = { 
    /// this script really should be served as a resource embedded in the assembly of the module 
    /// especially to keep the keys syncronized 

    pollingInterval: 60000, // 60 second polling. Not horrible, except for the server logs. ;) 

    formsAuthAuditKey: ".formsauthticket", // convenience members 
    aspSessionAuditKey: ".aspnetsession", 

    errorCallback: function(key, xhr) { 
     /// <summary> 
     /// Default behavior is to redirect to Default and provide the xhr error status text 
     /// in the loggedout query param. 
     /// 
     /// You may replace this default behaviour with your own handler. 
     /// e.g. AsynchronousSessionAuditor.errorCallback = myMethod; 
     /// </summary> 
     /// <param name="key" type="String"></param> 
     /// <param name="xhr" type="XMLHttpRequest"></param> 
     window.location = "Default.aspx?loggedout=Error+" + xhr.statusText; 
    }, 

    timeoutCallback: function(key, xhr) { 
     /// <summary> 
     /// Default behavior is to redirect to Default and provide the key value 
     /// in the loggedout query param. 
     /// 
     /// You may replace this default behaviour with your own handler. 
     /// e.g. AsynchronousSessionAuditor.timeoutCallback= myMethod; 
     /// </summary> 
     /// <param name="key" type="String"></param> 
     /// <param name="xhr" type="XMLHttpRequest"></param>  
     window.location = "Default.aspx?loggedout=" + key; 
     // or just refresh. you will be sent to login.aspx 
    }, 

    statusCallback: function(value) { 
     /// <summary> 
     /// Default behavior is to do nothing, which is not very interesting. 
     /// This value is set when AsynchronousSessionAuditor.init is called 
     /// </summary> 
     /// <param name="value" type="String"> 
     /// The responseText of the audit request. Most certainly is a JavaScript Date 
     /// as a number. Just cast to date to get the requested expiration dateTime. 
     /// e.g. var exp = new Date(parseFloat(value)); if (isNaN(exp)){this should never happen} 
     /// </param> 

     window.location = "Default.aspx?loggedout=" + key; 
     // or just refresh. you will be sent to login.aspx 
    }, 

    createXHR: function() { 
     /// <summary> 
     /// This xhr factory is not the best I have see. 
     /// You may wish to replace it with another or 
     /// use your favorite ajax library to make the 
     /// call. 
     /// </summary> 
     var xhr; 

     if (window.XMLHttpRequest) { 
      xhr = new XMLHttpRequest(); 
     } 
     else if (window.ActiveXObject) { 
      xhr = new ActiveXObject('Microsoft.XMLHTTP'); 
     } 
     else { 
      throw new Error("Could not create XMLHttpRequest object."); 
     } 
     return xhr; 
    }, 


    auditSession: function(key) { 
     /// <summary> 
     /// Make a request that will be serviced by the audit module to determine the 
     /// state of the current FormsAuthentication ticket or Asp.Net session 
     /// 
     /// The return value is a JavaScript date, in numeric form, that represents the 
     /// expiration of the item specified by key. 
     /// Just cast it to date, i.e. new Date(parseFloat(xhr.resposeText)) 
     /// </summary> 
     /// <param name="key" type="String"> 
     /// the server key for the item to audit. 
     /// 
     /// use ".formsauthticket" to get the expiration dateTime for the forms authentication 
     /// ticket, if any. 
     /// 
     /// use ".aspnetsession" to get the expiration of the current ASP.Net session. 
     /// 
     /// Both have convenience members on this object. 
     /// </param> 

     var xhr = AsynchronousSessionAuditor.createXHR(); 

     xhr.open("GET", key, true); 

     xhr.onreadystatechange = function() { 
      if (xhr.readyState === 4) { 
       if (xhr.status != 200) { 
        AsynchronousSessionAuditor.errorCallback(key, xhr); 
       } 
       else { 

        var timeout = parseFloat(xhr.responseText) 
        if (isNaN(timeout) || (new Date(timeout) < new Date())) { 
         AsynchronousSessionAuditor.timeoutCallback(key, xhr); 
        } 
        else { 
         AsynchronousSessionAuditor.statusCallback(xhr.responseText); 
        } 
       } 

      } 
     }; 
     xhr.send(null); 
    }, 

    init: function(key, statusCallback) { 
     // set the statusCallback member for reference. 
     AsynchronousSessionAuditor.statusCallback = statusCallback; 
     // check right now 
     AsynchronousSessionAuditor.auditSession(key); 
     // and recurring 
     window.setInterval((function() { AsynchronousSessionAuditor.auditSession(key) }), AsynchronousSessionAuditor.pollingInterval); 
    } 
}; 



function callScriptMethod(url) { 
    /// <summary> 
    /// 
    /// Simply makes a bogus ScriptService call to a void PageMethod name DoSomething simulating 
    /// an async (Ajax) call. 
    /// This resets the session cookie in the same way a postback or refresh would. 
    /// 
    /// The same would apply to a ScriptService enabled XML Webservice call. 
    /// </summary> 

    var xhr = AsynchronousSessionAuditor.createXHR(); 
    xhr.open("POST", url, true); 
    xhr.onreadystatechange = function() { 
     if (xhr.readyState === 4) { 
      if (xhr.status != 200) { 
       alert("script method call failed:" + xhr.statusText); 
      } 
     } 
    }; 
    xhr.setRequestHeader("content-type", "application/json"); 
    var postData = null; 
    xhr.send(postData); 
} 

Использование

<script src="AsynchronousSessionAuditor.js" type="text/javascript"></script> 

<script type="text/javascript"> 

    function reportStatus(value) { 
     /// <summary> 
     /// In a typical session/ticket lifetime you might display a warning at T-5 minutes that the session 
     /// is expiring and require an action. 
     /// </summary> 

     document.getElementById("sessionTimeout").innerHTML = "Session expires in " + parseInt((new Date(parseFloat(value)) - new Date())/1000) + " seconds."; 
    } 

    function init() { 

     // default is 60 seconds. Our session is only 1 minute so lets get crazy and poll every second 
     AsynchronousSessionAuditor.pollingInterval = 1000; 
     AsynchronousSessionAuditor.init(AsynchronousSessionAuditor.aspSessionAuditKey, reportStatus); 
    } 

</script> 
+0

OH EM GEE Я искал что-то подобное в течение нескольких дней. Собираюсь попробовать завтра! :) – TheGeekYouNeed

+0

@Cen, круто. не забудьте сообщить мне, как это работает. Я собираюсь выкопать его и использовать его через несколько дней. –

+0

@SkySanders, я просто нашел это решение, спасибо! Мне потребовалось некоторое время, чтобы заставить его работать, но мне пришлось добавить «.formsauthticket» и «.aspnetsession» к сопоставлениям приложений в IIS, в частности, чтобы не проверять, существует ли файл. – chezy525

1

Другие ответы sugg показывая уведомление на странице, которая время от времени .. но я думаю, вы спрашиваете, как показать сообщение на странице, на которую перенаправляется пользователь.

Одна из возможностей заключается в том, чтобы просто передать параметр URL-адреса на стартовую страницу только по тайм-ауту сеанса. Затем ваш скрипт или код asp.net могут решить отобразить сообщение при наличии параметра.

+0

вопрос был отредактирован mark. вы правы, это как раз то, на что похоже. Теперь. лол. –

Смежные вопросы