Daniel Hutton
Daniel Hutton

Reputation: 1455

AngularFire2 route guards by user roles

I have an angular 2 app set up with an route guard which currently checks to see if the user is logged in or not. This works OK, but now I am trying to set up another route guard which not only checks that the user is logged in, but also whether or not they are an admin user.

This is what I have at the moment:

import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { AngularFire } from 'angularfire2';
import { AuthService } from './auth.service';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/first';
import 'rxjs/add/operator/take';

@Injectable()
export class AdminGuard implements CanActivate {

  constructor(
    private af: AngularFire,
    private authService: AuthService,
    private router: Router
  ) {

  }

  canActivate(route:ActivatedRouteSnapshot, state:RouterStateSnapshot):Observable<boolean> {

    let redirectURL:string = state.url;

    return this.af.auth.map((auth) =>  {
      if (auth == null) {
        this.authService.redirectURL = redirectURL;
        this.router.navigate(['/login']);
        return false;
      } else {

        return this.af.database.object('roles/admins/'+auth.uid, { preserveSnapshot: true })
          .take(1)
          .subscribe(res => {
            if (res.val()) {
              console.log('is admin, return true');
              return true;
            } else {
              console.log('access denied');
              this.router.navigate(['/']);
              return false;
            }
          });

      }
    }).first();

  }

}

At the moment when I try going to a route which is protected by this guard, I get the console.log output of 'is admin, return true', but then nothing happens. The new route isn't displayed and the app just stays in the current page.

Could someone tell me where I'm going wrong please? Thanks for any help.

Upvotes: 3

Views: 624

Answers (1)

Daniel Hutton
Daniel Hutton

Reputation: 1455

Got it working with this in the end:

let redirectURL:string = state.url;

return this.af.auth
  .flatMap(auth => {
    if (auth == null) {
      return new Promise(resolve => { resolve({}) });
    } else {
      return this.af.database.object(`roles/admins/${auth.uid}`);
    }
  })
  .map(data => {
    if (data.$value) {
      return data.$value;
    } else {
      // User doesn't have permission
      this.authService.redirectURL = redirectURL;
      this.router.navigate(['/404']);
      return false;
    }
  })
  .first();

Still needs testing but I got it finished quickly before leaving the office. Seems to work OK now :)

Upvotes: 1

Related Questions