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

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

我试图避免使用jQuery,但我找不到任何教程或文章如何在angularjs中做到这一点。 任何帮助,将不胜感激。

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

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

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

你需要开始的所有信息都在网站上 ,更多的细节在wiki中 。 但是,这里有一个configuration的片段,显示如何在超时时注销它们。

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

应该有不同的方法来做到这一点,每种方法都应该比另一种更适合特定的应用。 对于大多数应用程序,只需处理键或鼠标事件,并适当地启用/禁用注销计时器即可。 这就是说,在我的头顶上,一个“奇特的”AngularJS-y解决scheme正在监视摘要循环,如果最后[指定的时间]没有触发,那么注销。 像这样的东西。

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

查看使用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> 

下面的代码是纯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> 

UPDATE

我更新我的解决scheme@Tom的build议。

 <!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> 

点击这里查看Plunker的更新版本

与Boo的方法一起使用,但是不喜欢用户一旦运行另一个摘要就被踢开的事实,这意味着用户保持login状态,直到他尝试在页面内做一些事情,然后立即启动。

我试图强制退出使用间隔,如果最后一次行动时间超过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(); }); }); 

您也可以使用angular-activity-monitor以比注入多个提供者更直接的方式完成,它使用setInterval() (与angular度的$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 }); } 

我尝试了Buu的方法,由于触发消化器执行的事件数量太多,包括执行$ interval和$ timeout函数,所以无法完成。 这使得应用程序处于不pipe用户input如何都不会空闲的状态。

如果你真的需要跟踪用户闲置时间,我不确定是否有一个良好的angular度的方法。 我build议在这里https://github.com/witoldsz/angular-http-auth代表更好的方法。; 此方法将提示用户在采取需要凭据的操作时重新进行身份validation。 在用户authentication之后,先前失败的请求被重新处理并且应用程序继续,就好像什么也没有发生。

这可以解决您在用户会话过期时可能遇到的问题,因为即使他们的身份validation过期,他们仍然可以保留应用程序状态并且不会丢失任何工作。

如果你的客户端有一些会话(cookies,令牌等等),你也可以看他们,如果他们到期,就会触发你的注销过程。

 app.run(['$interval', function($interval) { $interval(function() { if (/* session still exists */) { } else { // log out of client } }, 1000); }]); 

更新:这是一个显示关注的庞然大物。 http://plnkr.co/edit/ELotD8W8VAeQfbYFin1W 。 这说明的是蒸煮器的运行时间只有在间隔滴答时才会更新。 一旦间隔达到最大计数,那么消化器将不再运行。

ng-Idle看起来像是要走的路,但我无法弄清楚Brian F的修改,也想暂时hibernate,也考虑了一个非常简单的用例。 我把它缩减到下面的代码。 它挂钩事件重置超时标志(懒惰地放在$ rootScope中)。 它只检测用户返回时发生的超时(并触发事件),但这对我来说已经足够了。 我不能得到angular的$位置在这里工作,但再次使用document.location.href完成工作。

在.config运行后,我在app.js中插入了它。

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

我觉得布欧的消化周期表是天才。 感谢分享。 正如其他人所指出的,$ interval也会导致摘要循环运行。 我们可以为了自动logging用户使用setInterval而不会导致摘要循环。

 app.run(function($rootScope) { var lastDigestRun = new Date(); setInterval(function () { var now = Date.now(); if (now - lastDigestRun > 10 * 60 * 1000) { //logout } }, 60 * 1000); $rootScope.$watch(function() { lastDigestRun = new Date(); }); }); 

我已经使用了ng-idle,并添加了一点注销和令牌null代码,它工作正常,你可以试试这个。 谢谢@HackedByChinese制作这么好的模块。

IdleTimeout我刚刚删除了我的会话数据和令牌。

这是我的代码

 $scope.$on('IdleTimeout', function () { closeModals(); delete $window.sessionStorage.token; $state.go("login"); $scope.timedout = $uibModal.open({ templateUrl: 'timedout-dialog.html', windowClass: 'modal-danger' }); });