Session idle timeout with logout implementation
This commit is contained in:
committed by
Jose Alberto Hernandez
parent
caf3d39719
commit
29d3d08e88
@@ -25,6 +25,8 @@ import { OAuth2Token } from './o-auth2-token.model';
|
||||
*/
|
||||
@Injectable()
|
||||
export class AuthenticationService {
|
||||
// User logged in boolean
|
||||
private userLoggedIn: boolean;
|
||||
|
||||
/** Denotes whether the user credentials should persist through sessions. */
|
||||
private rememberMe: boolean;
|
||||
@@ -57,6 +59,7 @@ export class AuthenticationService {
|
||||
constructor(private http: HttpClient,
|
||||
private alertService: AlertService,
|
||||
private authenticationInterceptor: AuthenticationInterceptor) {
|
||||
this.userLoggedIn = false;
|
||||
this.rememberMe = false;
|
||||
this.storage = sessionStorage;
|
||||
const savedCredentials = JSON.parse(
|
||||
@@ -169,6 +172,7 @@ export class AuthenticationService {
|
||||
* @param {Credentials} credentials Authenticated user credentials.
|
||||
*/
|
||||
private onLoginSuccess(credentials: Credentials) {
|
||||
this.userLoggedIn = true;
|
||||
if (environment.oauth.enabled) {
|
||||
this.authenticationInterceptor.setAuthorizationToken(credentials.accessToken);
|
||||
} else {
|
||||
@@ -202,6 +206,7 @@ export class AuthenticationService {
|
||||
this.authenticationInterceptor.removeAuthorization();
|
||||
this.setCredentials();
|
||||
this.resetDialog();
|
||||
this.userLoggedIn = false;
|
||||
return of(true);
|
||||
}
|
||||
|
||||
@@ -344,4 +349,11 @@ export class AuthenticationService {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get user logged in
|
||||
*/
|
||||
getUserLoggedIn(): boolean {
|
||||
return this.userLoggedIn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { AmountDisbursedPieComponent } from './dashboard/amount-disbursed-pie/am
|
||||
import { ClientTrendsBarComponent } from './dashboard/client-trends-bar/client-trends-bar.component';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { WarningDialogComponent } from './warning-dialog/warning-dialog.component';
|
||||
import { SessionTimeoutDialogComponent } from './timeout-dialog/session-timeout-dialog.component';
|
||||
|
||||
/**
|
||||
* Home Component
|
||||
@@ -35,7 +36,8 @@ import { WarningDialogComponent } from './warning-dialog/warning-dialog.componen
|
||||
AmountCollectedPieComponent,
|
||||
AmountDisbursedPieComponent,
|
||||
ClientTrendsBarComponent,
|
||||
WarningDialogComponent
|
||||
WarningDialogComponent,
|
||||
SessionTimeoutDialogComponent
|
||||
],
|
||||
providers: [ ]
|
||||
})
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { IdleTimeoutService } from './idle-timeout.service';
|
||||
|
||||
describe('IdleTimeoutService', () => {
|
||||
let service: IdleTimeoutService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(IdleTimeoutService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { environment } from 'environments/environment';
|
||||
import { interval, merge, fromEvent, Observable} from 'rxjs';
|
||||
import { takeUntil, repeat, map} from 'rxjs/operators';
|
||||
|
||||
/**
|
||||
* Idle timeout service used to track idle user
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class IdleTimeoutService {
|
||||
|
||||
// max timeout for an idle user
|
||||
readonly timeoutDelay = environment.session.timeout.idleTimeout || 300000; // 5 minutes
|
||||
|
||||
// observable timeout
|
||||
readonly $onSessionTimeout: Observable<void>;
|
||||
|
||||
constructor() {
|
||||
const events = ['mousemove', 'keydown', 'wheel', 'mousedown', 'scroll'];
|
||||
const $signal = merge(...events.map(eventName => fromEvent(document, eventName)));
|
||||
this.$onSessionTimeout = interval(this.timeoutDelay).pipe(
|
||||
takeUntil($signal),
|
||||
map(() => undefined),
|
||||
repeat()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<h1 mat-dialog-title>{{ 'labels.heading.Session Timeout' | translate }}</h1>
|
||||
<mat-dialog-content>{{ 'labels.text.Session timed out after a period of inactivity' | translate }}.</mat-dialog-content>
|
||||
<mat-dialog-actions>
|
||||
<button mat-raised-button color="primary" mat-dialog-close>{{ 'labels.buttons.Close' | translate }}</button>
|
||||
</mat-dialog-actions>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SessionTimeoutDialogComponent } from './session-timeout-dialog.component';
|
||||
|
||||
describe('SessionTimeoutDialogComponent', () => {
|
||||
let component: SessionTimeoutDialogComponent;
|
||||
let fixture: ComponentFixture<SessionTimeoutDialogComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ SessionTimeoutDialogComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(SessionTimeoutDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatDialogRef } from '@angular/material/dialog';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-session-timeout-dialog',
|
||||
templateUrl: './session-timeout-dialog.component.html',
|
||||
styleUrls: ['./session-timeout-dialog.component.scss']
|
||||
})
|
||||
export class SessionTimeoutDialogComponent implements OnInit {
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<SessionTimeoutDialogComponent>) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<h1 mat-dialog-title>{{ "labels.text."+title | translate }}</h1>
|
||||
<h1 mat-dialog-title>{{ "labels.text." + title | translate }}</h1>
|
||||
<mat-dialog-content>{{ "labels.text.Warning message" | translate }}</mat-dialog-content>
|
||||
<mat-dialog-actions>
|
||||
<button mat-raised-button color="primary" mat-dialog-close>{{ "labels.buttons."+buttonText | translate}}</button>
|
||||
<button mat-raised-button color="primary" mat-dialog-close>{{ "labels.buttons." + buttonText | translate}}</button>
|
||||
</mat-dialog-actions>
|
||||
@@ -3,6 +3,7 @@ import { Component, OnInit, HostListener, HostBinding } from '@angular/core';
|
||||
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
||||
/** rxjs Imports */
|
||||
import { merge } from 'rxjs';
|
||||
@@ -20,6 +21,8 @@ import { ThemeStorageService } from './shared/theme-picker/theme-storage.service
|
||||
import { AlertService } from './core/alert/alert.service';
|
||||
import { AuthenticationService } from './core/authentication/authentication.service';
|
||||
import { SettingsService } from './settings/settings.service';
|
||||
import { IdleTimeoutService } from './home/timeout-dialog/idle-timeout.service';
|
||||
import { SessionTimeoutDialogComponent } from './home/timeout-dialog/session-timeout-dialog.component';
|
||||
|
||||
/** Custom Items */
|
||||
import { Alert } from './core/alert/alert.model';
|
||||
@@ -95,6 +98,8 @@ export class WebAppComponent implements OnInit {
|
||||
* @param {SettingsService} settingsService Settings Service.
|
||||
* @param {AuthenticationService} authenticationService Authentication service.
|
||||
* @param {Dates} dateUtils Dates service.
|
||||
* @param {IdleTimeoutService} idle Idle timeout service.
|
||||
* @param {MatDialog} dialog Dialog component.
|
||||
*/
|
||||
constructor(private router: Router,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
@@ -106,7 +111,9 @@ export class WebAppComponent implements OnInit {
|
||||
private settingsService: SettingsService,
|
||||
private authenticationService: AuthenticationService,
|
||||
private themingService: ThemingService,
|
||||
private dateUtils: Dates) { }
|
||||
private dateUtils: Dates,
|
||||
private idle: IdleTimeoutService,
|
||||
private dialog: MatDialog) { }
|
||||
|
||||
@HostBinding('class') public cssClass: string;
|
||||
|
||||
@@ -210,6 +217,17 @@ export class WebAppComponent implements OnInit {
|
||||
this.settingsService.setTenantIdentifier(environment.fineractPlatformTenantId || 'default');
|
||||
}
|
||||
this.settingsService.setTenantIdentifiers(environment.fineractPlatformTenantIds.split(','));
|
||||
|
||||
// Subscribe to session timeout If IdleTimeout is higher than 0 (zero)
|
||||
if (environment.session.timeout.idleTimeout > 0) {
|
||||
this.idle.$onSessionTimeout.subscribe(() => {
|
||||
if (this.authenticationService.getUserLoggedIn()) {
|
||||
this.alertService.alert({type: 'Session timeout', message: this.translateService.instant('labels.text.Session timed out')});
|
||||
this.dialog.open(SessionTimeoutDialogComponent);
|
||||
this.logout();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
logout() {
|
||||
|
||||
Reference in New Issue
Block a user