2020年11月18日 星期三

[研究][JavaScript]Master Page 用 idle-timer.js 做 Session Time Out 前 N 秒自動彈出倒數計時對話盒視窗

[研究][JavaScript]Master Page 用 idle-timer.js 做 Session Time Out 前 N 秒自動彈出倒數計時對話盒視窗

2020-11-18

續這篇

[研究][JavaScript] 用 idle-timer.js 做 Session Time Out 前 N 秒自動彈出倒數計時對話盒視窗

http://shaurong.blogspot.com/2020/11/javascript-idle-timerjs-session-time.html


環境 Visual Studio 2019 v16.8.1 版 + C# + ASP.NET  + WebForm + 主版頁面 Master Page

NuGet 要安裝數個套件,jQuery, BootStrap, popper, moment,不確定是否可缺。

敝人測試用 BootStrap 3.5.1 或 4.x 都可以用。

jQuery Idle Timer Plugin 要手動下載,把 idle-timer.js 拿過來用 ( 一個檔案就好)

https://github.com/thorst/jquery-idletimer


Download

Compressed ~3kb

https://raw.github.com/thorst/jquery-idletimer/master/dist/idle-timer.min.js

Uncompressed ~11kb

https://raw.github.com/thorst/jquery-idletimer/master/dist/idle-timer.js

不要另存新檔,下載 src 目錄下的 idle-timer.js,那個不是。


正確的內容


根據下面網址,jQuery Idle Timer Plugin 目前為 v1.1.1 2020-06-25 版

https://raw.githubusercontent.com/thorst/jquery-idletimer/master/dist/idle-timer.min.js



packages.conf

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="bootstrap" version="3.4.1" targetFramework="net472" />
  <package id="jQuery" version="3.5.1" targetFramework="net472" />
  <package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="2.0.1" targetFramework="net472" />
  <package id="Moment.js" version="2.29.1" targetFramework="net472" />
  <package id="popper.js" version="1.16.1" targetFramework="net472" />
</packages>

Site1.Master


<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site1.master.cs" Inherits="WebApplication1.Site1" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <%--相依性可能影響順序先後,但這個順序可用--%>
    <script src="Scripts/jquery-3.5.1.js"></script>
    <script src="Scripts/idle-timer.js"></script>
    <link href="Content/bootstrap.css" rel="stylesheet" />
    <script src="Scripts/popper.js"></script>
    <script src="Scripts/bootstrap.js"></script>
    <script src="Scripts/moment.js"></script>
    <asp:ContentPlaceHolder ID="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form id="form1" runat="server">
        <div class="container">
            <h2>Concept</h2>
            <p>
                Wait 10 seconds, you will see a expiring warning. Wait 10 more seconds and you will see that you have been logged out.
       
            </p>

        </div>
        <div class="modal fade" id="mdlExpirationWarning" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true" data-backdrop="static" data-keyboard="false">
            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title" id="exampleModalLabel">Session Expiration Warning</h5>

                    </div>
                    <div class="modal-body">
                        <p>You've been inactive for a while. For your security, we'll log you out automatically. Click "Stay Online" to continue your session. </p>
                        <p>
                            Your session will expire in <span class="bold" id="sessionSecondsRemaining">120</span> seconds.
                   
                        </p>
                    </div>
                    <div class="modal-footer">
                        <button id="extendSession" type="button" class="btn btn-primary" data-dismiss="modal">
                            Stay
                        Online</button>
                        <button id="logoutSession" type="button" class="btn btn-secondary">Logout</button>
                    </div>
                </div>
            </div>
        </div>

        <div class="modal fade" id="mdlLoggedOut" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true" data-backdrop="static" data-keyboard="false">
            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title" id="exampleModalLabel">You have been logged out</h5>
                    </div>
                    <div class="modal-body">
                        <p>Your session has expired.</p>
                    </div>
                </div>
            </div>
        </div>
        <div>
            <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
            </asp:ContentPlaceHolder>
        </div>
    </form>
    <script>
        // You could pull this out to its own file very easily
        window.app = window.app || {};

        app.session = {

            //Settings
            warningTimeout: 10000, //(ms) The time we give them to say they want to stay signed in
            inactiveTimeout: 20000, //(ms) The time until we display a warning message
            minWarning: 5000, //(ms) If they come back to page (on mobile), The minumum amount, before we just log them out
            timerSyncId: "SomethingUnique", //The key idleTimer will use to write to localStorage
            logoutUrl: "/logout", //Your url to log out, if you want you could build the url to pass a referal param
            keepAliveUrl: "api/user/KeepAlive", // The url for the keepalive api
            keepaliveInterval: 5000, //(ms) the interval to call keep alive url
            //From here down you shouldnt have to alter anything
            warningStart: null, //Date time the warning was started
            warningTimer: null, //Timer running every second to countdown to logout
            keepaliveTimer: null, //Timer for independent ping to keep session alive
            logout: function () {
                //Write to storage to tell other tab its time to sign out
                if (typeof (localStorage) !== "undefined") {
                    localStorage.setItem(app.session.timerSyncId, 0);
                }

                //Send this page to the logout url, that will destroy session and forward to login
                //window.location = app.session.logoutUrl;

                //To simulate logout we are just showing the logout dialog and locking the screen
                $("#mdlExpirationWarning").modal("hide");
                $("#mdlLoggedOut").modal("show");
            },
            keepAlive: function () {
                //Hide logout modal
                $("#mdlExpirationWarning").modal("hide");

                //Clear the timer
                clearTimeout(app.session.warningTimer);
                app.session.warningTimer = null;

                //Restart the idleTimer
                $(document).idleTimer("reset");
            },
            startKeepAliveTimer: function () {
                // Basically I just poll the server half way through the session life
                // to make sure the servers session stays valid
                clearTimeout(app.session.keepaliveTimer);
                app.session.keepaliveTimer = setInterval(function () {
                    app.session.sendKeepAlive();
                }, (app.session.inactiveTimeout / 2));
            },
            sendKeepAlive: function () {
                // Write a new date to storage so any other tabs are informed that this tab
                //  sent the keepalive
                if (typeof (localStorage) !== "undefined") {
                    localStorage.setItem(app.session.timerSyncId + "_keepalive", +new Date());
                }

                // The actual call to the keep alive api
                //$.post(app.session.keepAliveUrl).fail(function (jqXHR) {
                //    if (jqXHR.status == 500 || jqXHR.status == 0) {
                //        app.session.logout();
                //    }
                //});
            },
            showWarning: function (obj) {
                //Get time when user was last active
                var diff = (+new Date()) - obj.lastActive - obj.timeout,
                    warning = (+new Date()) - diff;

                // Destroy idleTimer so users are forced to click the extend button
                $(document).idleTimer("pause");

                //On mobile js is paused, so see if this was triggered while we were sleeping
                if (diff >= app.session.warningTimeout || warning <= app.session.minWarning) {
                    app.session.logout();
                } else {

                    //Show dialog, and note the time
                    $('#sessionSecondsRemaining').html(Math.round((app.session.warningTimeout - diff) / 1000));
                    $("#mdlExpirationWarning").modal("show");
                    app.session.warningStart = (+new Date()) - diff;

                    //Update counter downer every second
                    app.session.warningTimer = setInterval(function () {
                        var remaining = Math.round((app.session.warningTimeout / 1000) - (((+new Date()) - app.session.warningStart) / 1000));

                        if (remaining >= 0) {
                            $('#sessionSecondsRemaining').html(remaining);
                        } else {
                            app.session.logout();
                        }
                    }, 1000)
                }
            },
            localWrite: function (e) {

                if (typeof (localStorage) !== "undefined" && e.originalEvent.key == app.session.timerSyncId && app.session.warningTimer != null) {
                    // If another tab has written to cache then
                    if (e.originalEvent.newValue == 0) {
                        // If they wrote a 0 that means they chose to logout when prompted
                        app.session.logout();
                    } else {
                        // They chose to stay online, so hide the dialog
                        app.session.keepAlive();
                    }

                } else if (typeof (localStorage) !== "undefined" && e.originalEvent.key == app.session.timerSyncId + "_keepalive") {
                    // If the other tab sent a keepAlive poll to the server, reset the time here so we dont send two updates
                    // This isnt really needed per se but it will save some server load
                    app.session.startKeepAliveTimer();
                }
            }
        };

        $(function () {
            //This will fire at X after page load, to show an inactive warning
            $(document).on("idle.idleTimer", function (event, elem, obj) {
                app.session.showWarning(obj);
            });

            //Create a timer to keep server session alive, independent of idleTimer
            app.session.startKeepAliveTimer();

            //User clicked ok to extend session
            $("#extendSession").click(function () {
                app.session.keepAlive(); //Remove the warning dialog etc
            });

            //User clicked logout
            $("#logoutSession").click(function () {
                app.session.logout();
            });

            //Set up the idleTimer, if inactive for X seconds log them out
            $(document).idleTimer({
                timeout: app.session.inactiveTimeout - app.session.warningTimeout,
                timerSyncId: app.session.timerSyncId
            });

            // Monitor writes by other tabs
            $(window).bind("storage", app.session.localWrite);
        });
    </script>
</body>
</html>

Site1.Master.cs  (不用特別去修改)


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebApplication1
{
    public partial class Site1 : System.Web.UI.MasterPage
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }
    }
}

Default.aspx  (不用特別去修改)


<%@ Page Title="" Language="C#" MasterPageFile="~/Site1.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1.Default" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
</asp:Content>

Default.aspx.cs  (不用特別去修改)


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebApplication1
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }
    }
}

Web.Config (預設 20 分鐘,可以不用特別去設定)

<configuration>
  <system.web>
    <sessionState timeout="20"></sessionState>
  </system.web>
</configuration>

(下圖)執行結果,等10秒就會出現




(完)

相關

[研究] AjaxControlToolkit ToolkitScriptManager 元素不是已知元素
http://shaurong.blogspot.com/2020/11/ajaxcontroltoolkit-toolkitscriptmanager.html

[研究][JavaScript][C#][ASP.NET][WebForm] 主版頁面 Master Page 用 idle-timer.js 做 Session Time Out 前 N 秒自動彈出倒數計時對話盒視窗 (目前推薦)
https://shaurong.blogspot.com/2020/11/javascriptcaspnetwebform-master-page.html

[研究][JavaScript] 用 idle-timer.js 做 Session Time Out 前 N 秒自動彈出倒數計時對話盒視窗
http://shaurong.blogspot.com/2020/11/javascript-idle-timerjs-session-time.html

[研究][JavaScript][C#][ASP.NET][WenForm] 主版頁面 Master Page 用 timeout-dialog.js 做 Session Time Out 前 60 秒自動彈出倒數計時對話盒視窗
http://shaurong.blogspot.com/2020/11/javascriptcaspnetwenform-master-page.html

[研究][JavaScript] 用 timeout-dialog.js 做 Session Time Out 前 60 秒自動彈出倒數計時對話盒視窗
http://shaurong.blogspot.com/2020/11/javascript-timeout-dialogjs-session.html

[研究][C#][ASP.NET][WebForm] Sessionn Time Out 自動登出前倒數計時
http://shaurong.blogspot.com/2020/11/caspnetwebform-sessionn-time-out.html

[研究][C#][ASP.NET][WebForm] Master Page 的 Sessionn Time Out 自動登出前倒數計時 (目前推薦)
http://shaurong.blogspot.com/2020/11/caspnetwebform-master-page-sessionn.html

[研究][C#][ASP.NET][WebForm][JavaScript]顯示 Web.Config 設定 Session Out Time 時間
http://shaurong.blogspot.com/2020/11/caspnetwebformjavascript-webconfig.html


沒有留言:

張貼留言