16

ネイティブフォーム認証およびセッション機能を使用するASP.NET4.5WebFormsアプリケーションがあります。どちらも20分のタイムアウトがあり、有効期限がスライドします。

次のシナリオを想像してみてください。ユーザーがアプリケーションでしばらく作業した後、他のことを実行し、アプリケーションを20分間アイドル状態のままにします。次に、ユーザーはアプリケーションに戻ってレポートを作成します。ただし、ユーザーが保存しようとすると、ログイン画面が表示され、レポートは失われます。

明らかに、これは望ましくありません。このシナリオの代わりに、認証またはセッションのいずれかが期限切れになった瞬間に、ブラウザーをログインページにリダイレクトする必要があります。これを実現するために、これが当てはまるかどうかを確認するために呼び出すことができるWebApiサービスを構築しました。

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;
    }
}

このWebApiサービスは、認証またはセッションのいずれかが期限切れになっていないかどうかを確認するために、クライアントによって10秒ごとに呼び出されます。その場合、スクリプトはブラウザをログインページにリダイレクトします。これは魅力のように機能します。

ただし、このサービスを呼び出すと、認証とセッションの両方の有効期限がスライドしてトリガーされます。したがって、基本的に、終了しない認証とセッションを作成します。サービスの開始時にブレークポイントを設定して、これをトリガーする独自の関数の1つであるかどうかを確認しました。ただし、これは当てはまりません。サービスの実行前に、ASP.NETのどこかで発生しているようです。

  1. 特定の要求に対してASP.NETの認証とセッションスライドの有効期限のトリガーを無効にする方法はありますか?
  2. そうでない場合、このようなシナリオに取り組むためのベストプラクティスは何ですか?
4

3 に答える 3

13
  1. これは不可能のようです。スライド有効期限が有効になると、常にトリガーされます。セッションを拡張せずにセッションにアクセスする方法がある場合、それを見つけることができませんでした。

  2. では、このシナリオにどのように取り組むべきでしょうか? 質問で最初に提案されたものに代わる次の解決策を思いつきました。これは、Web サービスを使用して x 秒ごとに家に電話をかけないため、実際にはより効率的です。

そのため、ASP.NET のフォーム認証またはセッションのいずれかが期限切れになったことを知る方法が必要です。これにより、ユーザーを事前にログアウトできるようになります。ユーザーが同時に複数のブラウザー ウィンドウ/タブでアプリケーションを操作する可能性があるため、すべてのページに単純な JavaScript タイマー ( Khalid Abuhakmeh によって提案されたもの) では十分ではありません。

この問題を簡単にするために最初に決定したのは、セッションの有効期限をフォーム認証の有効期限よりも数分長くすることです。これにより、フォーム認証の前にセッションが期限切れになることはありません。ユーザーが次にログインしようとしたときに古いセッションが残っている場合は、それを破棄して新しいセッションを強制します。

これで、フォーム認証の有効期限を考慮するだけで済みます。

次に、フォーム認証の自動スライド有効期限 (web.config で設定) を無効にし、独自のバージョンを作成することにしました。

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);
    }
}

このメソッドは、OnPreRenderComplete他のすべてのページが継承するアプリケーションの BasePage クラスのイベントから呼び出します。これは、通常のスライド有効期限機能とまったく同じことを行いますが、いくつかの追加機能を実行する機会があります。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);
}

これで、ユーザーが別のブラウザー ウィンドウ/タブで作業している場合でも、常に正しいフォーム認証の有効期限を表す追加の Cookie を自由に使用できます。結局のところ、Cookie はブラウザ全体に適用されます。残っているのは、Cookie の値を確認するための JavaScript 関数だけです。

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);
    }
}

( jQuery Cookie Pluginを使用して Cookie を取得することに注意してください。)

この機能を間隔を置いて配置すると、ユーザーはフォーム認証の有効期限が切れた瞬間にログアウトされます。ほら :-) この実装の追加特典は、フォーム認証の有効期限がいつ延長されるかを制御できるようになったことです。有効期限を延長しない一連の Web サービスが必要な場合は、RenewAuthenticationTicketそれらのメソッドを呼び出さないでください。

追加するものがある場合は、コメントをドロップしてください!

于 2013-04-04T16:08:07.583 に答える
0

これはすべてクライアント側で解決でき、サーバーに戻る必要はありません。

JavaScript でこれを行います。

 var timeout = setTimeout(function () {
      window.location = "/login";
 }, twentyMinutesInMilliseconds + 1);

タイムアウトは、ページが更新されるたびに 20 分に設定されます。これにより、ユーザーはタイムアウトが発生する前にすべての作業を完了する必要があります。多くのサイトがこの方法を使用しており、不要なサーバー リクエストを行う必要がありません。

于 2013-03-27T17:15:23.940 に答える