I have an app that I want to limit to both logged in and verified users. I was able to make two separate guards (logged-in.guard.ts
and verified.guard.ts
), but since one guard was dependant on the other guard, I made a third guard that combined the two (logged-in-and-verified.guard.ts
). I appreciate any feedback, because I am new to angular guards; specifically, is there a better way to do this? It seemed a bit convoluted to me.
The code does work currently.
logged-in.guard.ts
import {Injectable} from '@angular/core';
import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router} from '@angular/router';
import {Observable} from 'rxjs/Observable';
import {AngularFireAuth} from 'angularfire2/auth';
import * as firebase from 'firebase/app';
@Injectable()
export class LoggedInGuard implements CanActivate {
user: Observable<firebase.User>;
constructor(private auth: AngularFireAuth, private router: Router) {
this.user = auth.authState;
}
canActivate(next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> {
const url = state.url; // store current url
return this.checkLogin();
}
checkLogin(): Observable<boolean> {
let loggedIn;
return this.user.map(u => {
loggedIn = !!u; // if u, return true, else return false
if (loggedIn) {
return true;
} else {
// re-route them to the login page
this.router.navigate(['/login']);
return false;
}
});
}
}
verified.guard.ts
import {Injectable} from '@angular/core';
import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router} from '@angular/router';
import {Observable} from 'rxjs/Observable';
import {AngularFireAuth} from 'angularfire2/auth';
import {AngularFireDatabase} from 'angularfire2/database';
@Injectable()
export class VerifiedGuard implements CanActivate {
loggedIn: boolean;
constructor(private afAuth: AngularFireAuth, private db: AngularFireDatabase) {
}
canActivate(next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> {
if (!this.loggedIn) { // this Guard is always dependant of being logged in
return Observable.of(false);
}
return this.checkVerified();
}
checkVerified() {
if (this.afAuth.auth.currentUser) {
const uid = this.afAuth.auth.currentUser.uid;
return this.db.object('/users/' + uid).map(userObj => {
if (userObj.$exists()) {
return userObj.verified;
} else {
return false;
}
});
}
return Observable.of(false);
}
}
logged-in-and-verified.guard.ts
import {Injectable} from '@angular/core';
import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router} from '@angular/router';
import {Observable} from 'rxjs/Observable';
import {LoggedInGuard} from './logged-in.guard';
import {VerifiedGuard} from './verified.guard';
import 'rxjs/add/operator/mergeMap';
@Injectable()
export class LoggedInAndVerifiedGuard implements CanActivate {
constructor(private _loggedInGuard: LoggedInGuard, private _verifiedGuard: VerifiedGuard,
private router: Router) {
}
canActivate(next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> {
return this.checkLoginAndVerified(next, state);
}
checkLoginAndVerified(next, state) {
return this._loggedInGuard.canActivate(next, state).map((loggedInRes) => {
return loggedInRes;
}).mergeMap(loggedInVal => {
if (loggedInVal) {
this._verifiedGuard.loggedIn = loggedInVal;
return this._verifiedGuard.canActivate(next, state).map((verifiedRes) => {
this.router.navigate(['/unverified']);
return verifiedRes;
});
} else {
return Observable.of(false);
}
});
}
}
version info (in case it matters)
@angular/cli: 1.0.0
node: 7.7.3
os: darwin x64
@angular/animations: 4.1.0
@angular/common: 4.1.0
@angular/compiler: 4.1.0
@angular/core: 4.1.0
@angular/forms: 4.1.0
@angular/http: 4.1.0
@angular/material: 2.0.0-beta.3
@angular/platform-browser: 4.1.0
@angular/platform-browser-dynamic: 4.1.0
@angular/router: 4.1.0
@angular/cli: 1.0.0
@angular/compiler-cli: 4.1.0