Auto logout with Angularjs based on idle user

前端 未结 10 661
面向向阳花
面向向阳花 2020-11-30 18:07

Is it possible to determine if a user is inactive and automatically log them out after say 10 minutes of inactivity using angularjs?

I was trying to avoid using jQue

相关标签:
10条回答
  • 2020-11-30 18:34

    I wrote a module called Ng-Idle that may be useful to you in this situation. Here is the page which contains instructions and a demo.

    Basically, it has a service that starts a timer for your idle duration that can be disrupted by user activity (events, such as clicking, scrolling, typing). You can also manually interrupt the timeout by calling a method on the service. If the timeout is not disrupted, then it counts down a warning where you could alert the user they are going to be logged out. If they do not respond after the warning countdown reaches 0, an event is broadcasted that your application can respond to. In your case, it could issue a request to kill their session and redirect to a login page.

    Additionally, it has a keep-alive service that can ping some URL at an interval. This can be used by your app to keep a user's session alive while they are active. The idle service by default integrates with the keep-alive service, suspending the pinging if they become idle, and resuming it when they return.

    All the info you need to get started is on the site with more details in the wiki. However, here's a snippet of config showing how to sign them out when they time out.

    angular.module('demo', ['ngIdle'])
    // omitted for brevity
    .config(function(IdleProvider, KeepaliveProvider) {
      IdleProvider.idle(10*60); // 10 minutes idle
      IdleProvider.timeout(30); // after 30 seconds idle, time the user out
      KeepaliveProvider.interval(5*60); // 5 minute keep-alive ping
    })
    .run(function($rootScope) {
        $rootScope.$on('IdleTimeout', function() {
            // end their session and redirect to login
        });
    });
    
    0 讨论(0)
  • 2020-11-30 18:36

    You could also accomplish using angular-activity-monitor in a more straight forward way than injecting multiple providers and it uses setInterval() (vs. angular's $interval) to avoid manually triggering a digest loop (which is important to prevent keeping items alive unintentionally).

    Ultimately, you just subscribe to a few events that determine when a user is inactive or becoming close. So if you wanted to log out a user after 10 minutes of inactivity, you could use the following snippet:

    angular.module('myModule', ['ActivityMonitor']);
    
    MyController.$inject = ['ActivityMonitor'];
    function MyController(ActivityMonitor) {
      // how long (in seconds) until user is considered inactive
      ActivityMonitor.options.inactive = 600;
    
      ActivityMonitor.on('inactive', function() {
        // user is considered inactive, logout etc.
      });
    
      ActivityMonitor.on('keepAlive', function() {
        // items to keep alive in the background while user is active
      });
    
      ActivityMonitor.on('warning', function() {
        // alert user when they're nearing inactivity
      });
    }
    
    0 讨论(0)
  • 2020-11-30 18:38

    Played with Boo's approach, however don't like the fact that user got kicked off only once another digest is run, which means user stays logged in until he tries to do something within the page, and then immediatelly kicked off.

    I am trying to force the logoff using interval which checks every minute if last action time was more than 30 minutes ago. I hooked it on $routeChangeStart, but could be also hooked on $rootScope.$watch as in Boo's example.

    app.run(function($rootScope, $location, $interval) {
    
        var lastDigestRun = Date.now();
        var idleCheck = $interval(function() {
            var now = Date.now();            
            if (now - lastDigestRun > 30*60*1000) {
               // logout
            }
        }, 60*1000);
    
        $rootScope.$on('$routeChangeStart', function(evt) {
            lastDigestRun = Date.now();  
        });
    });
    
    0 讨论(0)
  • 2020-11-30 18:38

    I have used ng-idle for this and added a little logout and token null code and it is working fine, you can try this. Thanks @HackedByChinese for making such a nice module.

    In IdleTimeout i have just deleted my session data and token.

    Here is my code

    $scope.$on('IdleTimeout', function () {
            closeModals();
            delete $window.sessionStorage.token;
            $state.go("login");
            $scope.timedout = $uibModal.open({
                templateUrl: 'timedout-dialog.html',
                windowClass: 'modal-danger'
            });
        });
    
    0 讨论(0)
  • 2020-11-30 18:39

    View Demo which is using angularjs and see your's browser log

    <!DOCTYPE html>
    <html ng-app="Application_TimeOut">
    <head>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.min.js"></script>
    </head>
    
    <body>
    </body>
    
    <script>
    
    var app = angular.module('Application_TimeOut', []);
    app.run(function($rootScope, $timeout, $document) {    
        console.log('starting run');
    
        // Timeout timer value
        var TimeOutTimerValue = 5000;
    
        // Start a timeout
        var TimeOut_Thread = $timeout(function(){ LogoutByTimer() } , TimeOutTimerValue);
        var bodyElement = angular.element($document);
    
        /// Keyboard Events
        bodyElement.bind('keydown', function (e) { TimeOut_Resetter(e) });  
        bodyElement.bind('keyup', function (e) { TimeOut_Resetter(e) });    
    
        /// Mouse Events    
        bodyElement.bind('click', function (e) { TimeOut_Resetter(e) });
        bodyElement.bind('mousemove', function (e) { TimeOut_Resetter(e) });    
        bodyElement.bind('DOMMouseScroll', function (e) { TimeOut_Resetter(e) });
        bodyElement.bind('mousewheel', function (e) { TimeOut_Resetter(e) });   
        bodyElement.bind('mousedown', function (e) { TimeOut_Resetter(e) });        
    
        /// Touch Events
        bodyElement.bind('touchstart', function (e) { TimeOut_Resetter(e) });       
        bodyElement.bind('touchmove', function (e) { TimeOut_Resetter(e) });        
    
        /// Common Events
        bodyElement.bind('scroll', function (e) { TimeOut_Resetter(e) });       
        bodyElement.bind('focus', function (e) { TimeOut_Resetter(e) });    
    
        function LogoutByTimer()
        {
            console.log('Logout');
    
            ///////////////////////////////////////////////////
            /// redirect to another page(eg. Login.html) here
            ///////////////////////////////////////////////////
        }
    
        function TimeOut_Resetter(e)
        {
            console.log('' + e);
    
            /// Stop the pending timeout
            $timeout.cancel(TimeOut_Thread);
    
            /// Reset the timeout
            TimeOut_Thread = $timeout(function(){ LogoutByTimer() } , TimeOutTimerValue);
        }
    
    })
    </script>
    
    </html>
    

    Below code is pure javascript version

    <html>
        <head>
            <script type="text/javascript">         
                function logout(){
                    console.log('Logout');
                }
    
                function onInactive(millisecond, callback){
                    var wait = setTimeout(callback, millisecond);               
                    document.onmousemove = 
                    document.mousedown = 
                    document.mouseup = 
                    document.onkeydown = 
                    document.onkeyup = 
                    document.focus = function(){
                        clearTimeout(wait);
                        wait = setTimeout(callback, millisecond);                       
                    };
                }           
            </script>
        </head> 
        <body onload="onInactive(5000, logout);"></body>
    </html>
    

    UPDATE

    I updated my solution as @Tom suggestion.

    <!DOCTYPE html>
    <html ng-app="Application_TimeOut">
    <head>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.min.js"></script>
    </head>
    
    <body>
    </body>
    
    <script>
    var app = angular.module('Application_TimeOut', []);
    app.run(function($rootScope, $timeout, $document) {    
        console.log('starting run');
    
        // Timeout timer value
        var TimeOutTimerValue = 5000;
    
        // Start a timeout
        var TimeOut_Thread = $timeout(function(){ LogoutByTimer() } , TimeOutTimerValue);
        var bodyElement = angular.element($document);
    
        angular.forEach(['keydown', 'keyup', 'click', 'mousemove', 'DOMMouseScroll', 'mousewheel', 'mousedown', 'touchstart', 'touchmove', 'scroll', 'focus'], 
        function(EventName) {
             bodyElement.bind(EventName, function (e) { TimeOut_Resetter(e) });  
        });
    
        function LogoutByTimer(){
            console.log('Logout');
            ///////////////////////////////////////////////////
            /// redirect to another page(eg. Login.html) here
            ///////////////////////////////////////////////////
        }
    
        function TimeOut_Resetter(e){
            console.log(' ' + e);
    
            /// Stop the pending timeout
            $timeout.cancel(TimeOut_Thread);
    
            /// Reset the timeout
            TimeOut_Thread = $timeout(function(){ LogoutByTimer() } , TimeOutTimerValue);
        }
    
    })
    </script>
    </html>
    

    Click here to see at Plunker for updated version

    0 讨论(0)
  • 2020-11-30 18:39

    ng-Idle looks like the way to go, but I could not figure out Brian F's modifications and wanted to timeout for a sleeping session too, also I had a pretty simple use case in mind. I pared it down to the code below. It hooks events to reset a timeout flag (lazily placed in $rootScope). It only detects the timeout has happened when the user returns (and triggers an event) but that's good enough for me. I could not get angular's $location to work here but again, using document.location.href gets the job done.

    I stuck this in my app.js after the .config has run.

    app.run(function($rootScope,$document) 
    {
      var d = new Date();
      var n = d.getTime();  //n in ms
    
        $rootScope.idleEndTime = n+(20*60*1000); //set end time to 20 min from now
        $document.find('body').on('mousemove keydown DOMMouseScroll mousewheel mousedown touchstart', checkAndResetIdle); //monitor events
    
        function checkAndResetIdle() //user did something
        {
          var d = new Date();
          var n = d.getTime();  //n in ms
    
            if (n>$rootScope.idleEndTime)
            {
                $document.find('body').off('mousemove keydown DOMMouseScroll mousewheel mousedown touchstart'); //un-monitor events
    
                //$location.search('IntendedURL',$location.absUrl()).path('/login'); //terminate by sending to login page
                document.location.href = 'https://whatever.com/myapp/#/login';
                alert('Session ended due to inactivity');
            }
            else
            {
                $rootScope.idleEndTime = n+(20*60*1000); //reset end time
            }
        }
    });
    
    0 讨论(0)
提交回复
热议问题