我们正在根据用户角色维护会话。我们想在会话空闲5分钟时实现超时功能。我们正在使用@ ng-idle / core npm模块来做到这一点。
我的服务文件:
import { ActivatedRouteSnapshot } from '@angular/router';
import { RouterStateSnapshot } from '@angular/router';
import {Idle, DEFAULT_INTERRUPTSOURCES, EventTargetInterruptSource} from
'@ng-idle/core';
@Injectable()
export class LoginActService implements CanActivate {
constructor(private authService: APILogService, private router:
Router,private idle: Idle) {
idle.setIdle(10);
idle.setTimeout(10);
}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean>|Promise<boolean>|boolean {
let role = localStorage.getItem('currentUser');
if (localStorage.getItem('currentUser')) {
if(next.data[0] == role){
},600000)
return true;
}
}
else{
this.router.navigate(['/'], { queryParams: { returnUrl: state.url }});
return false;
}
}
}
作为示例,我使用了setIdle超时5秒钟,但这没有发生。有人可以指导我怎么做吗?
答案 0 :(得分:2)
您可以将bn-ng-idle npm用于角度应用程序中的用户空闲/会话超时检测。
npm install bn-ng-idle
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { BnNgIdleService } from 'bn-ng-idle'; // import bn-ng-idle service
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [BnNgIdleService], // add it to the providers of your module
bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts
import { Component } from '@angular/core';
import { BnNgIdleService } from 'bn-ng-idle'; // import it to your component
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private bnIdle: BnNgIdleService) { // initiate it in your component constructor
this.bnIdle.startWatching(300).subscribe((res) => {
if(res) {
console.log("session expired");
}
})
}
}
在上面的示例中,我用 300秒(5分钟)调用了startWatching(timeOutSeconds)
方法并订阅了可观察对象,一旦用户闲置了五分钟,则使用subscribe方法将使用res参数的值(为布尔值)为true调用。
通过检查res是否正确,可以显示会话超时对话框或消息。为简便起见,我只是将消息记录到控制台。
答案 1 :(得分:1)
超时后,我在 Angular8 中添加了 this.bnIdle.stopTimer()
,因为当我访问同一个组件时,时间会出现故障。
--> 我在 ngOnDestroy 中订阅和取消订阅,但后来计时器没有停止。
--> 找到了 stopTimer
并实施了它,它对我来说非常好。希望能帮到其他人。
this.bnIdle.startWatching(300).subscribe((res) => {
if(res) {
console.log("session expired");
this.bnIdle.stopTimer();
}
});
答案 2 :(得分:0)
选项:1: angular-user-idle。
逻辑
图书馆正在等待用户1分钟的不活动状态(60 秒)。
如果检测到无效,则onTimerStart()
被触发并
返回倒计时2分钟(120秒)。
如果用户未通过stopTimer()停止计时器,则时间在2点后结束 分钟(120秒)和onTimeout()触发。
在AppModule中:
@NgModule({
imports: [
BrowserModule,
// Optionally you can set time for `idle`, `timeout` and `ping` in seconds.
// Default values: `idle` is 600 (10 minutes), `timeout` is 300 (5 minutes)
// and `ping` is 120 (2 minutes).
UserIdleModule.forRoot({idle: 600, timeout: 300, ping: 120})
],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
In any of your core componets:
ngOnInit() {
//Start watching for user inactivity.
this.userIdle.startWatching();
// Start watching when user idle is starting.
this.userIdle.onTimerStart().subscribe(count => console.log(count));
// Start watch when time is up.
this.userIdle.onTimeout().subscribe(() => console.log('Time is up!'));
}
奖金: 您可以使用“ ping”发出请求,以在给定的时间间隔(例如,每10分钟)中刷新令牌。
选项:2:使用ngrx
请参考链接中的文章: https://itnext.io/inactivity-auto-logout-w-angular-and-ngrx-3bcb2fd7983f
答案 3 :(得分:0)
您可以在主组件或父组件上使用以下代码。假设这是在 管理父组件,并假设您具有身份验证服务,因此 您可以知道用户是否已登录
声明变量
userActivity;
userInactive: Subject<any> = new Subject();
在构造函数中或在ngOnInit上添加
this.setTimeout();
this.userInactive.subscribe(() => {
this.logout();
});
logout() {
this.authService.logout();
this.authService.redirectLogoutUser();
}
最后添加以下方法
setTimeout() {
this.userActivity = setTimeout(() => {
if (this.authService.isLoggedIn) {
this.userInactive.next(undefined);
console.log('logged out');
}
}, 420000);
}
@HostListener('window:mousemove') refreshUserState() {
clearTimeout(this.userActivity);
this.setTimeout();
}
答案 4 :(得分:0)
timer = 0;
setInterval(() => {
if (window.localStorage['userStoredToken']) {
let clearTimer = localStorage.getItem('time-limit');
if (clearTimer == 'clear-now') {
this.timer = 0;
setTimeout(() => {
localStorage.removeItem('time-limit');
}, 5000);
}
this.timer++;
if (this.timer > 2000) { // no of seconds after which user needs to logout
this.logoutSessionTimeOut();
}
}
}, 1000);
@HostListener('mouseup', ['$event'])
@HostListener('mousemove', ['$event'])
onEvent(event: MouseEvent) {
this.timer = 0;
localStorage.setItem('time-limit', "clear-now");
}
@HostListener('document:keydown', ['$event']) onKeydownHandler(event: KeyboardEvent) {
this.timer = 0;
localStorage.setItem('time-limit', "clear-now");
}
答案 5 :(得分:0)
我对我发现的一些方法并不感到兴奋,包括一些 npm 包,所以我为 angular 设计了一些非常简单的东西。您只需在 app.component 中导入服务并调用它的 init() 方法。唯一棘手的部分是处理跨选项卡操作对话框的关闭。需要注意的是,用于存储的 windoweventlistener 仅在当前文档(也就是另一个窗口或选项卡)之外的存储被更改时才会做出反应。
import { Injectable, NgZone, OnDestroy } from '@angular/core';
import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { UserService } from '@common/services/user.service';
import { takeWhile } from 'rxjs/operators';
import { IdleTimeoutActions, IDLE_LOGOUT_TIME, IDLE_TIMEOUT_ACTION, IDLE_TIMEOUT_TIME } from './IdleTimeoutActions';
import { InactivityTimeoutModalComponent } from './inactivity-timeout-modal/inactivity-timeout-modal.component';
@Injectable({
providedIn: 'root'
})
export class IdleTimeoutService implements OnDestroy {
alive = true;
interval;
timeoutSetExpiredTime;
boundUpdateExpiredTime;
boundOnIdleTimeoutAction;
inactivityDialogRef: MatDialogRef<InactivityTimeoutModalComponent>;
dialogConfig: MatDialogConfig = {
panelClass: ['confirmation-dialog', 'l-w400'],
disableClose: true
};
dialogOpen = false;
currentStatus;
constructor(private dialog: MatDialog,
private userService: UserService,
private zone: NgZone,
private router: Router) {}
init() {
this.boundUpdateExpiredTime = this.updateExpiredTime.bind(this);
this.boundOnIdleTimeoutAction = this.onIdleTimeoutAction.bind(this);
this.userService.isLoggedIn().pipe(takeWhile(x => this.alive)).subscribe(userIsLoggedIn=> {
if(userIsLoggedIn) {
this.currentStatus = window.localStorage.getItem(IDLE_TIMEOUT_ACTION);
if(this.currentStatus === IdleTimeoutActions.LOGOUT) { // if the user is logged in, reset the idletimeoutactions to null
window.localStorage.setItem(IDLE_TIMEOUT_ACTION, null);
}
window.addEventListener('storage', this.boundOnIdleTimeoutAction); // handle dialog action events from other tabs
this.startTrackingIdleTime();
}
});
}
/**
* Starts the interval that checks localstorage to determine if the idle expired time is at it's limit
*/
startTrackingIdleTime() {
this.addListeners();
if(window.localStorage.getItem(IDLE_TIMEOUT_ACTION) !== IdleTimeoutActions.IDLE_TRIGGERED) {
this.updateExpiredTime(0);
}
if(this.interval) {
clearInterval(this.interval);
}
this.interval = setInterval(() => {
const expiredTime = parseInt(localStorage.getItem('_expiredTime'), 10);
if(expiredTime + (IDLE_LOGOUT_TIME * 1000) < Date.now()) {
this.triggerLogout();
} else if (expiredTime < Date.now()) {
if(!this.dialogOpen) {
window.localStorage.setItem(IDLE_TIMEOUT_ACTION, IdleTimeoutActions.IDLE_TRIGGERED);
this.openIdleDialog();
}
}
}, 1000);
}
triggerLogout() {
this.removeListeners();
// triggers other tabs to logout
window.localStorage.setItem(IDLE_TIMEOUT_ACTION, IdleTimeoutActions.LOGOUT);
this.dialog.closeAll();
this.userService.logout();
localStorage.setItem(IDLE_TIMEOUT_ACTION, null);
}
/**
* Update the _exporedTime localStorage variable with a new time (timeout used to throttle)
*/
updateExpiredTime(timeout = 300) {
if(window.localStorage.getItem(IDLE_TIMEOUT_ACTION) !== IdleTimeoutActions.IDLE_TRIGGERED) {
if (this.timeoutSetExpiredTime) {
clearTimeout(this.timeoutSetExpiredTime);
}
this.timeoutSetExpiredTime = setTimeout(() => {
this.zone.run(() => {
localStorage.setItem('_expiredTime', '' + (Date.now() + (IDLE_TIMEOUT_TIME * 1000)));
});
}, timeout);
}
}
addListeners() {
this.zone.runOutsideAngular(() => {
window.addEventListener('mousemove', this.boundUpdateExpiredTime);
window.addEventListener('scroll', this.boundUpdateExpiredTime);
window.addEventListener('keydown', this.boundUpdateExpiredTime);
});
}
removeListeners() {
window.removeEventListener('mousemove', this.boundUpdateExpiredTime);
window.removeEventListener('scroll', this.boundUpdateExpiredTime);
window.removeEventListener('keydown', this.boundUpdateExpiredTime);
window.removeEventListener('storage', this.boundOnIdleTimeoutAction);
clearInterval(this.interval);
}
openIdleDialog() {
this.dialogOpen = true;
this.inactivityDialogRef = this.dialog.open(InactivityTimeoutModalComponent, this.dialogConfig);
this.inactivityDialogRef.afterClosed().subscribe(action => {
if(action === IdleTimeoutActions.CONTINUE) {
this.updateExpiredTime(0);
// trigger other tabs to close the modal
localStorage.setItem(IDLE_TIMEOUT_ACTION, IdleTimeoutActions.CONTINUE);
localStorage.setItem(IDLE_TIMEOUT_ACTION, null);
} else if(action === IdleTimeoutActions.LOGOUT){
this.triggerLogout();
}
this.dialogOpen = false;
});
}
onIdleTimeoutAction = (event) => {
if (event.storageArea === localStorage) {
if(this.dialogOpen) {
const action = localStorage.getItem(IDLE_TIMEOUT_ACTION);
if(action === IdleTimeoutActions.LOGOUT) {
this.removeListeners();
this.dialog.closeAll();
this.router.navigate(['login']);
} else if (action === IdleTimeoutActions.CONTINUE) {
this.updateExpiredTime(0);
this.inactivityDialogRef?.close(IdleTimeoutActions.CONTINUE);
}
}
}
}
ngOnDestroy() {
this.removeListeners();
this.alive = false;
}
}