如何在角度6中赋予会话空闲超时?

时间:2019-02-28 12:06:30

标签: angular session angular6

我们正在根据用户角色维护会话。我们想在会话空闲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秒钟,但这没有发生。有人可以指导我怎么做吗?

6 个答案:

答案 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;
  }
}