Angular 2 : So schützt du Routes mit Guards
Sicherer Code bleibt zeitlos. In diesem Beitrag erfährst du, wie du mit Angular-Guards Zugriffe auf sensible Bereiche kontrollierst und dein Routing sauber absicherst. Egal ob für Login-Prüfungen, Berechtigungen oder sauberes Verlassen von Views: Dieses Wissen ist auch für moderne Angular-Versionen relevant und praxisnah.
Angular 2 hat mit «Guards» ein Feature eingeführt, mit dem du vor dem Auflösen einer Route bestimmte Kriterien prüfen kannst.
Dieses Angular 2-Feature ist gerade bei sicherheitsrelevanten Daten oder Views sinnvoll, da du aufgrund eines Tokens oder eines bestimmten Claims im Token prüfen kannst, ob du mit dem Token x auf eine bestimmte Route zugreifen darfst.
|
Was ist Angular 2?Angular 2 ist die zweite komplett überarbeitete Version des OpenSource Frameworks AngularJS von Google. Das Webframework kommt beim Erstellen von Single-Page-Applikationen zum Einsatz. |
Angular 2 bietet zum Schützen von Routen vier Guards an: CanLoad, CanActivate, CanActivateChild, CanDeactivate.
Anmerkung: Ein Angular 2 Guard kann ein observable <boolean>, ein promise <boolean> oder ein boolean zurückgeben. Bei den asynchronen Operatoren wird gewartet, bis das Ergebnis true oder false ist. In den Beispielen in diesem Beitrag schauen wir uns nur die boolschen Operatoren true/false an.
Angular 2 Guard CanActivate
CanActivate prüft in Angular 2 vor dem Laden der Route, ob diese aufgelöst werden kann. Der Guard selber lässt sich am besten in einer Klasse implementieren. Er implementiert das CanActivate-Interface, und die gleichnamige Methode muss die Parameter «ActivatedRouteSnapshot» und «RouterStateSnapshot» als Parameter empfangen.
import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
@Injectable()
export class AuthenticationGuard implements CanActivate {
constructor(private router: Router) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
let url: string = state.url;
return this.userIsLoggedIn(url);
}
private userIsLoggedIn(url: string): boolean {
return true;
}
}
Die Klasse muss dazu mit dem Injectable-Attribut markiert und als Provider im dazugehörigen Modul angeboten werden.
@NgModule({
imports:
// ...
,
declarations:
// ...
,
providers:
AuthenticationGuard
,
// ...
})
Anschliessend kannst du im Router-Modul den CanActivate-Guard für die entsprechende Route aktivieren.
import { Routes } from '@angular/router';
import { HomeComponent } from './components/home/home.component';
import { AboutComponent } from './components/about/about.component';
import { AuthenticationGuard } from './guards/authentication';
export const AppRoutes: Routes =
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent, canActivate: [AuthenticationGuard }
];

Auf dem Screenshot sieht man, dass die Route noch nicht aufgelöst wurde, der Guard aber durchlaufen wird. Eine Möglichkeit des Guards wäre nun, auf eine andere Route umzuleiten, wenn du nicht eingeloggt bist oder nicht über entsprechende Rechte verfügst.
Guards werden in Angular 2 in einem Array angegeben. Daher kannst du Guards auch aneinanderreihen.
{ path: 'about', component: AboutComponent, canActivate: AuthenticationGuard, XyzGuard, ... }
Angular 2 Guard CanActivateChild
Der Angular 2 Guard «CanActivateChild» ist im Prinzip genau dasselbe wie der «CanActivate», es wird jedoch auf Child-Ebene im Routing-Modul angegeben.
Angular 2 Guard CanDeactivate
Der Guard «CanDeactivate» ist das Gegenteil von CanActivate: Er prüft also, ob eine Route verlassen werden darf. Beispielsweise, falls ungespeicherte Änderungen auf der Seite sind oder du aus anderen Gründen das Verlassen einer Seite bestätigen lassen willst.
import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { AboutComponent } from '../components/about/about.component';
@Injectable()
export class CanDeactivateGuard implements CanDeactivate {
canDeactivate(component: AboutComponent) {
// parameter “component” represents your component here
return component.MyCanDeactivate ? component.MyCanDeactivate() : true;
}
}
Hierbei sieht man, dass der CanDeactivate-Guard generisch ist und den konkreten Komponententyp kennt. Einen Verweis auf die Instanz bekommst du als Parameter im Konstruktor übergeben. Du kannst dann auf ihm durch einen Methodenaufruf beispielsweise abfragen, ob die Route verlassen werden darf oder nicht.
Wieder kann der Angular 2 Guard in der Route mit der entsprechenden Property angegeben werden.
import { Routes } from '@angular/router';
import { HomeComponent } from './components/home/home.component';
import { AboutComponent } from './components/about/about.component';
import { AuthenticationGuard } from './guards/authenticationGuard';
import { CanDeactivateGuard } from './guards/canDeactivateGuard';
export const AppRoutes: Routes =
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent,
canActivate: [AuthenticationGuard,
canDeactivate: CanDeactivateGuard
}
];
Angular 2 Guard CanLoad
Den CanLoad-Guard kannst du benutzen, wenn du Routen erst gar nicht laden willst bzw. wenn sie gar nicht geladen werden können. Die Routen sollen erst geladen werden, wenn ein bestimmtes Kriterium erfüllt ist.
Die Implementierung ist ähnlich wie bei den vorherigen Guards. Wieder wird das «CanLoad» importiert und implementiert.
import { Injectable } from '@angular/core';
import { CanLoad, Route } from '@angular/router';
@Injectable()
export class CanLoadGuard implements CanLoad {
constructor() { }
canLoad(route: Route): boolean {
// return if criteial is fulfilled
console.log("In Canload");
return true;
}
}
Der CanLoad-Guard funktioniert nur mit Lazy-Loading. Die Route wird durch Lazy-Loading nachgeladen, sobald die CanLoad-Methode nach Überprüfung eines Kriteriums true zurückgibt.
Fazit zu Route Guards in Angular 2
Somit sind Guards in Angular 2 ein sehr mächtiges Werkzeug, wenn du das Laden von Routen einschränken oder verhindern willst. Durch die Verwendung von eigenen Typescript-Klassen und der Angabe in den Routen des Moduls bleiben die Kriterien übersichtlich und gut testbar – einer der vielen Vorteile von Angular 2.
