使用基于空闲用户的Angularjs自动注销

use*_*411 77 angularjs ng-idle

是否可以确定用户是否处于非活动状态,并在使用angularjs说不活动10分钟后自动将其注销?

我试图避免使用jQuery,但我找不到有关如何在angularjs中执行此操作的任何教程或文章.任何帮助,将不胜感激.

Hac*_*ese 111

我写了一个名为的模块Ng-Idle,在这种情况下可能对你有用.这是包含说明和演示的页面.

基本上,它有一个服务,可以为您的空闲时间启动计时器,可以被用户活动(事件,如点击,滚动,键入)中断.您还可以通过调用服务上的方法手动中断超时.如果超时没有中断,那么它会倒计时警告,您可以提醒用户他们将要注销.如果他们在警告倒计时达到0后没有响应,则会广播您的应用程序可以响应的事件.在您的情况下,它可以发出请求以终止其会话并重定向到登录页面.

此外,它还有一个保持活动的服务,可以间隔ping一些URL.您的应用可以使用它来保持用户会话处于活动状态时保持活动状态.默认情况下,空闲服务与保持活动服务集成,如果它们变为空闲则暂停ping,并在它们返回时恢复它.

您需要开始的所有信息都在网站上,并在维基中提供更多详细信息.但是,这里有一个配置片段,显示如何在超时时签名.

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
    });
});
Run Code Online (Sandbox Code Playgroud)

  • @BrianF谢谢你.我意识到你使用的是定制版本,所以它可能并不重要,但我会将其添加到正式版本中. (3认同)
  • 嘿,你的方法对我来说非常合适,直到我遇到移动Safari的问题,当页面进入后台时暂停超时.我不得不修改它以在每个手表上设置一个空闲时间戳,然后在中断时更新.在每次中断更新之前,我都会检查idleTimeout是否已经过期,这可以解决Safari问题(不会自动注销,但会在第一次触摸/鼠标/单击时注销). (2认同)

Fra*_*Thu 20

查看正在使用的演示angularjs并查看您的浏览器日志

<!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>
Run Code Online (Sandbox Code Playgroud)

下面的代码是纯javascript版本

<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>
Run Code Online (Sandbox Code Playgroud)

UPDATE

我更新了我的解决方案@Tom建议.

<!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>
Run Code Online (Sandbox Code Playgroud)

点击此处查看Plunker的更新版本

  • 通过对事件名称进行循环可以缩短一个很酷的解决方案:var eventNames = ['keydown','keyup','click','mousemove','DOMMouseScroll','mousewheel','mousedown','touchstart' ,'touchmove','滚动','焦点']; for(var i = 0; i <eventNames.length; i ++){bodyElement.bind(eventNames [i],TimeOut_Resetter); } (2认同)

Buu*_*yen 19

应该有不同的方法来实现它,每种方法都应该比其他方法更适合特定的应用程序.对于大多数应用程序,您只需处理键或鼠标事件,并适当地启用/禁用注销计时器.也就是说,在我的头脑中,一个"花哨的"AngularJS-y解决方案正在监视摘要循环,如果没有在最后[指定的持续时间]内触发,则注销.像这样的东西.

app.run(function($rootScope) {
  var lastDigestRun = new Date();
  $rootScope.$watch(function detectIdle() {
    var now = new Date();
    if (now - lastDigestRun > 10*60*60) {
       // logout here, like delete cookie, navigate to login ...
    }
    lastDigestRun = now;
  });
});
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是一个非常新颖的解决方案,并且相当多地使用它.我遇到的主要问题是,这将运行许多其他可能不是用户驱动的事件($ interval,$ timeouts等),这些事件将重置你的lastDigestRun. (4认同)
  • "如果(现在 - lastDigestRun> 10*60*60){"这是否意味着我必须等待1分钟? (2认同)

v-t*_*tec 11

使用Boo的方法,但是不喜欢用户在运行另一个摘要时才开始启动的事实,这意味着用户保持登录状态,直到他尝试在页面内执行某些操作,然后立即启动.

我试图使用间隔来强制注销,如果上次操作时间超过30分钟,则会每分钟检查一次.我把它挂在$ routeChangeStart上,但也可以挂钩$ rootScope.$ watch就像在Boo的例子中一样.

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();  
    });
});
Run Code Online (Sandbox Code Playgroud)


Sea*_*n3z 6

您还可以使用angular-activity-monitor比注入多个提供程序更直接的方式使用它并使用setInterval()(与角度相比$interval)来避免手动触发摘要循环(这对于防止项目无意中保持活动非常重要).

最后,您只需订阅一些事件,以确定用户何时处于非活动状态或关闭状态.因此,如果您想在10分钟不活动后注销用户,可以使用以下代码段:

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
  });
}
Run Code Online (Sandbox Code Playgroud)