Merge pull request #263 in TEA/mina-sidor-fa-web from feature/TV-892-inactivity-check to develop
Squashed commit of the following:
commit 0a6b323e5d8d94c18ebada2cdb47a6a48f0f32bd
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date: Fri Nov 12 14:20:21 2021 +0100
Changed variable name after PR
commit 1cb495e7db4365720c1276959d77bc1f6d460c6f
Merge: 2bfe34ac b5071fcf
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date: Fri Nov 12 14:18:11 2021 +0100
Merge branch 'develop' into feature/TV-892-inactivity-check
commit 2bfe34acc5eb5e2c6260624de7c0d0c9c5a1728b
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date: Fri Nov 12 13:45:31 2021 +0100
Added check on last activity after application close
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
import { DOCUMENT } from '@angular/common';
|
import { DOCUMENT } from '@angular/common';
|
||||||
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, HostListener, Inject } from '@angular/core';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
|
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
|
||||||
|
import { APPLICATION_CLOSED_TIME_STAMP } from '@msfa-constants/local-storage-keys';
|
||||||
import { environment } from '@msfa-environment';
|
import { environment } from '@msfa-environment';
|
||||||
import { AuthenticationService } from '@msfa-services/api/authentication.service';
|
import { AuthenticationService } from '@msfa-services/api/authentication.service';
|
||||||
import { IdleService } from '@msfa-services/api/idle.service';
|
import { IdleService } from '@msfa-services/api/idle.service';
|
||||||
@@ -18,6 +19,13 @@ export class AppComponent {
|
|||||||
userIsIdle$: Observable<boolean> = this.idleService.isIdle$;
|
userIsIdle$: Observable<boolean> = this.idleService.isIdle$;
|
||||||
timeLeftBeforeLogout$: Observable<string> = this.idleService.timeLeftBeforeLogout$;
|
timeLeftBeforeLogout$: Observable<string> = this.idleService.timeLeftBeforeLogout$;
|
||||||
|
|
||||||
|
// Saving latest activity timestamp when application is closed
|
||||||
|
// to avoid users be automatically logged in if user hasn't used the application for a while.
|
||||||
|
@HostListener('window:beforeunload')
|
||||||
|
saveApplicationClosedTimestamp(): void {
|
||||||
|
localStorage.setItem(APPLICATION_CLOSED_TIME_STAMP, new Date().getTime().toString());
|
||||||
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DOCUMENT) private document: Document,
|
@Inject(DOCUMENT) private document: Document,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ export const AUTH_TOKEN_KEY = 'id_token';
|
|||||||
export const AUTH_TOKEN_EXPIRE_KEY = 'expires_at';
|
export const AUTH_TOKEN_EXPIRE_KEY = 'expires_at';
|
||||||
export const AUTH_TOKEN_EXPIRES_IN_KEY = 'expires_in';
|
export const AUTH_TOKEN_EXPIRES_IN_KEY = 'expires_in';
|
||||||
export const SELECTED_ORGANIZATION_NUMBER_KEY = 'selected_orgnr';
|
export const SELECTED_ORGANIZATION_NUMBER_KEY = 'selected_orgnr';
|
||||||
|
export const APPLICATION_CLOSED_TIME_STAMP = 'application_closed';
|
||||||
|
|
||||||
export const ALL_LOCAL_STORAGE_KEYS = [
|
export const ALL_LOCAL_STORAGE_KEYS = [
|
||||||
AUTH_TOKEN_KEY,
|
AUTH_TOKEN_KEY,
|
||||||
AUTH_TOKEN_EXPIRE_KEY,
|
AUTH_TOKEN_EXPIRE_KEY,
|
||||||
AUTH_TOKEN_EXPIRES_IN_KEY,
|
AUTH_TOKEN_EXPIRES_IN_KEY,
|
||||||
SELECTED_ORGANIZATION_NUMBER_KEY,
|
SELECTED_ORGANIZATION_NUMBER_KEY,
|
||||||
|
APPLICATION_CLOSED_TIME_STAMP,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Injectable } from '@angular/core';
|
|||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import {
|
import {
|
||||||
ALL_LOCAL_STORAGE_KEYS,
|
ALL_LOCAL_STORAGE_KEYS,
|
||||||
|
APPLICATION_CLOSED_TIME_STAMP,
|
||||||
AUTH_TOKEN_EXPIRES_IN_KEY,
|
AUTH_TOKEN_EXPIRES_IN_KEY,
|
||||||
AUTH_TOKEN_EXPIRE_KEY,
|
AUTH_TOKEN_EXPIRE_KEY,
|
||||||
AUTH_TOKEN_KEY,
|
AUTH_TOKEN_KEY,
|
||||||
@@ -10,7 +11,7 @@ import {
|
|||||||
import { environment } from '@msfa-environment';
|
import { environment } from '@msfa-environment';
|
||||||
import { AuthenticationResponse } from '@msfa-models/api/authentication.response.model';
|
import { AuthenticationResponse } from '@msfa-models/api/authentication.response.model';
|
||||||
import { Authentication, mapAuthApiResponseToAuthenticationResult } from '@msfa-models/authentication.model';
|
import { Authentication, mapAuthApiResponseToAuthenticationResult } from '@msfa-models/authentication.model';
|
||||||
import { add, isBefore, sub } from 'date-fns';
|
import { add, isAfter, isBefore, sub } from 'date-fns';
|
||||||
import { BehaviorSubject, combineLatest, Observable, of } from 'rxjs';
|
import { BehaviorSubject, combineLatest, Observable, of } from 'rxjs';
|
||||||
import { catchError, distinctUntilChanged, filter, map, tap } from 'rxjs/operators';
|
import { catchError, distinctUntilChanged, filter, map, tap } from 'rxjs/operators';
|
||||||
|
|
||||||
@@ -37,8 +38,19 @@ export class AuthenticationService {
|
|||||||
]).pipe(
|
]).pipe(
|
||||||
filter(([token, expiresAt]) => !!(token && expiresAt)),
|
filter(([token, expiresAt]) => !!(token && expiresAt)),
|
||||||
map(([, expiresAt]) => {
|
map(([, expiresAt]) => {
|
||||||
|
const now = new Date();
|
||||||
|
const applicationClosedTimeStamp = localStorage.getItem(APPLICATION_CLOSED_TIME_STAMP);
|
||||||
|
// Checking to see if the user has been active on the page within the last hour
|
||||||
|
const applicationClosedWithin1Hour =
|
||||||
|
!applicationClosedTimeStamp || isAfter(+applicationClosedTimeStamp, sub(now, { hours: 1 }));
|
||||||
|
const isValid = isBefore(now, sub(expiresAt, { minutes: 1 })) && applicationClosedWithin1Hour;
|
||||||
|
|
||||||
|
if (applicationClosedTimeStamp) {
|
||||||
|
localStorage.removeItem(APPLICATION_CLOSED_TIME_STAMP);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isValid: isBefore(new Date(), sub(expiresAt, { minutes: 1 })),
|
isValid,
|
||||||
isRefreshable: false,
|
isRefreshable: false,
|
||||||
// isRefreshable: isBefore(new Date(), expiresAt),
|
// isRefreshable: isBefore(new Date(), expiresAt),
|
||||||
};
|
};
|
||||||
@@ -102,16 +114,18 @@ export class AuthenticationService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _localStorageData(): { id_token: string; expires_at: number; expires_in: number } {
|
private get _localStorageData(): { idToken: string; expiresAt: number; expiresIn: number; lastActive: number } {
|
||||||
const id_token = localStorage.getItem(AUTH_TOKEN_KEY);
|
const idToken = localStorage.getItem(AUTH_TOKEN_KEY);
|
||||||
const expiresAt = localStorage.getItem(AUTH_TOKEN_EXPIRE_KEY);
|
const expiresAt = localStorage.getItem(AUTH_TOKEN_EXPIRE_KEY);
|
||||||
const expiresIn = localStorage.getItem(AUTH_TOKEN_EXPIRES_IN_KEY);
|
const expiresIn = localStorage.getItem(AUTH_TOKEN_EXPIRES_IN_KEY);
|
||||||
|
const lastActive = localStorage.getItem(APPLICATION_CLOSED_TIME_STAMP);
|
||||||
|
|
||||||
return id_token && expiresAt && expiresIn
|
return idToken && expiresAt && expiresIn
|
||||||
? {
|
? {
|
||||||
id_token,
|
idToken,
|
||||||
expires_at: +JSON.parse(expiresAt),
|
expiresAt: +expiresAt,
|
||||||
expires_in: +expiresIn,
|
expiresIn: +expiresIn,
|
||||||
|
lastActive: +lastActive,
|
||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
@@ -130,9 +144,9 @@ export class AuthenticationService {
|
|||||||
const localStorageData = this._localStorageData;
|
const localStorageData = this._localStorageData;
|
||||||
|
|
||||||
if (localStorageData) {
|
if (localStorageData) {
|
||||||
this._token$.next(localStorageData.id_token);
|
this._token$.next(localStorageData.idToken);
|
||||||
this._expiresAt$.next(localStorageData.expires_at);
|
this._expiresAt$.next(localStorageData.expiresAt);
|
||||||
this._expiresIn$.next(localStorageData.expires_in);
|
this._expiresIn$.next(localStorageData.expiresIn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user