From ed396c773a9d7f0b853e91a931d03d71162c5f9e Mon Sep 17 00:00:00 2001 From: Amadeusz Starzykiewicz Date: Wed, 26 Oct 2016 09:40:33 +0200 Subject: [PATCH] [DNCR-107] Improve homepage guarding and redirection This commit also contains some minor changes to how being logged in is checked. --- frontend/src/app/_commons/auth/auth-guard.ts | 8 ++-- .../src/app/_commons/auth/auth.service.ts | 46 +++++++++---------- frontend/src/app/app.component.ts | 6 +-- frontend/src/app/app.module.ts | 4 +- frontend/src/app/app.routes.ts | 8 ++-- frontend/src/app/homepage/homepage-guard.ts | 20 ++++++++ .../src/app/homepage/homepage.component.ts | 3 -- frontend/src/app/homepage/index.ts | 1 + .../src/app/homepage/login/login.component.ts | 2 +- frontend/tslint.json | 1 - 10 files changed, 58 insertions(+), 41 deletions(-) create mode 100644 frontend/src/app/homepage/homepage-guard.ts diff --git a/frontend/src/app/_commons/auth/auth-guard.ts b/frontend/src/app/_commons/auth/auth-guard.ts index 2b4265d..71fc846 100644 --- a/frontend/src/app/_commons/auth/auth-guard.ts +++ b/frontend/src/app/_commons/auth/auth-guard.ts @@ -5,15 +5,17 @@ import { Observable } from 'rxjs/Observable'; @Injectable() export class AuthGuard implements CanActivate { - constructor(private router: Router, private authService: AuthService) { + constructor(private router: Router) { } canActivate(): Observable { - let isLoggedIn = this.authService.isLoggedIn(); + let isLoggedIn = AuthService.isLoggedIn(); if (!isLoggedIn){ // TODO: Add "login required" message ;) - this.router.navigate(['/']); + if (this.router.url !== '/') { + this.router.navigate(['/']); + } } return Observable.of(isLoggedIn); diff --git a/frontend/src/app/_commons/auth/auth.service.ts b/frontend/src/app/_commons/auth/auth.service.ts index da3cb31..a596e11 100755 --- a/frontend/src/app/_commons/auth/auth.service.ts +++ b/frontend/src/app/_commons/auth/auth.service.ts @@ -1,7 +1,6 @@ import { Injectable } from '@angular/core'; import { CookieService } from 'angular2-cookie/core'; import { Response } from '@angular/http'; -import { Router } from '@angular/router'; import { tokenNotExpired, JwtHelper } from 'angular2-jwt'; import { Observable } from 'rxjs/Observable'; import * as moment from 'moment'; @@ -12,16 +11,16 @@ import { AuthHttp } from './http'; @Injectable() export class AuthService { private static TOKEN = 'id_token'; - private static refreshTimeout: any; - public KNOWN_USER = 'known_user'; + private static KNOWN_USER = 'known_user'; + private static refreshTimeoutId: any; - public static clear() { - clearTimeout(AuthService.refreshTimeout); - localStorage.removeItem(AuthService.TOKEN); + constructor(private cookies: CookieService, private http: AuthHttp) { + this.scheduleTokenRefreshing(); } - constructor(private cookies: CookieService, private http: AuthHttp, private router: Router) { - this.scheduleTokenRefreshing(); + public static clear() { + clearTimeout(AuthService.refreshTimeoutId); + localStorage.removeItem(AuthService.TOKEN); } public login(model: LoginModel): Observable { @@ -34,45 +33,42 @@ export class AuthService { .do(() => AuthService.clear()); } - public isLoggedIn(): boolean { + public static isLoggedIn(): boolean { try { - if (!tokenNotExpired()){ - if (this.router.url !== '/') { - this.router.navigate(['/']); - } - return false; - } - - return true; + return tokenNotExpired(); } catch (e) { return false; } } public isKnownUser(): boolean { - return this.cookies.get(this.KNOWN_USER) === 'true'; + return this.cookies.get(AuthService.KNOWN_USER) === 'true'; } private saveToken(response: Response) { localStorage.setItem(AuthService.TOKEN, response.json().token); - this.cookies.put(this.KNOWN_USER, 'true'); + this.cookies.put(AuthService.KNOWN_USER, 'true'); this.scheduleTokenRefreshing(); } private scheduleTokenRefreshing() { - if (!this.isLoggedIn()) { + if (!AuthService.isLoggedIn()) { AuthService.clear(); return; } - let helper = new JwtHelper(); let token = localStorage.getItem(AuthService.TOKEN); - let expiry = helper.decodeToken(token).exp * 1000; - let now = moment().valueOf(); - let timeout = expiry - now - 60000; // Subtract 1 minute to be sure token is still valid + let timeout = AuthService.getTokenTimeout(token); - AuthService.refreshTimeout = setTimeout( + AuthService.refreshTimeoutId = setTimeout( () => this.http.post('/api/refresh-token', {}).subscribe((response) => this.saveToken(response)), timeout ); } + + private static getTokenTimeout(token: string): number { + let expiry = moment(new JwtHelper().getTokenExpirationDate(token)); + let now = moment(); + // Subtract 1 minute to be sure token is still valid + return moment.duration(expiry.diff(now)).subtract(1, 'minute').asMilliseconds(); + } } diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index d6b96ec..e494a5c 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -17,13 +17,13 @@ export class App { constructor(private router: Router, private authService: AuthService) { } - logout() { + public logout() { this.authService.logout().subscribe(() => { this.router.navigate(['/']); }); } - isLoggedIn() { - return this.authService.isLoggedIn(); + public isLoggedIn() { + return AuthService.isLoggedIn(); } } diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 04cbb20..714eea8 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -11,11 +11,11 @@ import { CommonsModule } from './_commons/commons.module'; import { App } from './app.component'; import { APP_RESOLVER_PROVIDERS } from './app.resolver'; import { NoContent } from './no-content'; -import { Homepage } from './homepage/homepage.component'; +import { Homepage, HomepageGuard } from './homepage'; // Application wide providers const APP_PROVIDERS = [ - ...APP_RESOLVER_PROVIDERS, CookieService, ...AUTH_PROVIDERS, { + ...APP_RESOLVER_PROVIDERS, CookieService, HomepageGuard, ...AUTH_PROVIDERS, { provide: XSRFStrategy, useValue: new CookieXSRFStrategy('XSRF-TOKEN', 'X-XSRF-TOKEN') } diff --git a/frontend/src/app/app.routes.ts b/frontend/src/app/app.routes.ts index a5a7a93..e2f1813 100644 --- a/frontend/src/app/app.routes.ts +++ b/frontend/src/app/app.routes.ts @@ -1,12 +1,14 @@ import { Routes } from '@angular/router'; -import { NoContent } from './no-content'; -import { Homepage } from './homepage/homepage.component'; import { AuthGuard } from 'app/_commons/auth'; +import { NoContent } from './no-content'; +import { Homepage, HomepageGuard } from './homepage'; export const ROUTES: Routes = [ { path: '', - component: Homepage + pathMatch: 'full', + component: Homepage, + canActivate: [HomepageGuard] }, { path: 'reception', diff --git a/frontend/src/app/homepage/homepage-guard.ts b/frontend/src/app/homepage/homepage-guard.ts new file mode 100644 index 0000000..17aeffe --- /dev/null +++ b/frontend/src/app/homepage/homepage-guard.ts @@ -0,0 +1,20 @@ +import { Injectable } from '@angular/core'; +import { Router, CanActivate } from '@angular/router'; +import { AuthService } from 'app/_commons/auth'; +import { Observable } from 'rxjs/Observable'; + +@Injectable() +export class HomepageGuard implements CanActivate { + constructor(private router: Router) { + } + + canActivate(): Observable { + let isLoggedIn = AuthService.isLoggedIn(); + + if (isLoggedIn){ + this.router.navigate(['/reception']); + } + + return Observable.of(!isLoggedIn); + } +} diff --git a/frontend/src/app/homepage/homepage.component.ts b/frontend/src/app/homepage/homepage.component.ts index ca92a63..50225b4 100755 --- a/frontend/src/app/homepage/homepage.component.ts +++ b/frontend/src/app/homepage/homepage.component.ts @@ -23,8 +23,5 @@ export class Homepage { ngOnInit() { this.isLoginVisible = this.service.isKnownUser(); - if (this.service.isLoggedIn()) { - this.router.navigate(['reception']); - } } } diff --git a/frontend/src/app/homepage/index.ts b/frontend/src/app/homepage/index.ts index b7156a9..1e968fc 100644 --- a/frontend/src/app/homepage/index.ts +++ b/frontend/src/app/homepage/index.ts @@ -1 +1,2 @@ export * from './homepage.component'; +export * from './homepage-guard'; diff --git a/frontend/src/app/homepage/login/login.component.ts b/frontend/src/app/homepage/login/login.component.ts index 1c383ea..893ae3b 100755 --- a/frontend/src/app/homepage/login/login.component.ts +++ b/frontend/src/app/homepage/login/login.component.ts @@ -34,7 +34,7 @@ export class LoginComponent { if (response.hasOwnProperty('error')) { this.error = response.error; } else { - this.error = 'Nieprawidłowy login lub hasło.'; + this.error = 'Nieoczekiwany błąd serwera.'; } } ); diff --git a/frontend/tslint.json b/frontend/tslint.json index 54ff41b..066d92c 100644 --- a/frontend/tslint.json +++ b/frontend/tslint.json @@ -7,7 +7,6 @@ "member-ordering": [ true, "public-before-private", - "static-before-instance", "variables-before-functions" ], "no-any": false,