0

I have an Angular application that has two guards. The first makes sure the user is authenticated, the second guard is to check the users role.

On some routes, the user should not be authenticated, so there are no guards. This is working fine.

On other routes, the user should be authenticated, but every role should be able to access it. So I use only the authguard. On other routes, only administrators should be able to access the route. This is where the issue lies.

The role guard runs when the authguard is described.

eg: on my route: /fetch-data only the authguard is specified, but the roleguard runs also.

Here are my guards and my modules:

authorize.guard.ts

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthorizeService } from './authorize.service';
import { tap } from 'rxjs/operators';
import { ApplicationPaths, QueryParameterNames } from './api-authorization.constants';

@Injectable({
  providedIn: 'root'
})
export class AuthorizeGuard implements CanActivate {
  constructor(private authorize: AuthorizeService, private router: Router) {
  }
  canActivate(
    _next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
      return this.authorize.isAuthenticated()
        .pipe(tap(isAuthenticated => this.handleAuthorization(isAuthenticated, state)));
  }

  private handleAuthorization(isAuthenticated: boolean, state: RouterStateSnapshot) {
    if (!isAuthenticated) {
      this.router.navigate(ApplicationPaths.LoginPathComponents, {
        queryParams: {
          [QueryParameterNames.ReturnUrl]: state.url
        }
      });
    }
  }
}

roles.guard.ts

import { RoleService } from './role.service';
import { HttpClient } from '@angular/common/http';
import { Inject, Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Observable, of } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AdminGuard implements CanActivate {
  constructor(private _roleService: RoleService) {
  }
  canActivate(
    _next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
      return this._roleService.checkRole('Administrator', _next);
}
}

app.module.ts

import { RoleService } from './../api-authorization/role.service';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { RouterModule } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AppComponent } from './app.component';
// material ui imports
[...]

import { ApiAuthorizationModule } from 'src/api-authorization/api-authorization.module';
import { AuthorizeGuard } from 'src/api-authorization/authorize.guard';
import { AuthorizeInterceptor } from 'src/api-authorization/authorize.interceptor';

import { WebshopComponent } from './webshop/webshop.component';
import { WebshopitemComponent } from './webshop/webshopitem/webshopitem.component';
import { KlassiekersComponent } from './klassiekers/klassiekers.component';

import { WijnenComponent } from './wijnen/wijnen.component';
// component imports
[...]
import { AdminGuard } from 'src/api-authorization/Roles.guard';


export function tokenGetter(){
  return localStorage.getItem("token");
}

@NgModule({
  declarations: [               
    AppComponent,
    NavMenuComponent,
    HomeComponent,
    // Component imports
    [...]
    ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    HttpClientModule,
    FormsModule,
    ApiAuthorizationModule,
    ReactiveFormsModule,
    // Material ui modules
[...]

    RouterModule.forRoot([
      { path: '', component: HomeComponent, pathMatch: 'full' },
      { path: 'webshop', component: WebshopComponent },
      { path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthorizeGuard] },
      { path: 'klassiekers', component: KlassiekersComponent},
      { path: 'shoppingcart', component: ShoppingcartComponent},
      { path: 'orders', component: OrderComponent, canActivate: [AuthorizeGuard] },
      { path: 'bevestiging/:UserId', component: BevestigingComponent, canActivate: [AuthorizeGuard]},
      { path: 'admin', canActivate: [AuthorizeGuard, AdminGuard], children: [
        { path: 'wijnen', component: WijnenComponent },
        { path: 'wijnen/insert', component: WijnenInsertComponent },
        { path: 'wijnen/update/:id', component: EditWijnenComponent },
      ]},
      { path: 'profile', canActivate: [AuthorizeGuard], children: [
        { path: 'orders', canActivate: [AdminGuard], component: OrdersComponent },
      ]}
    ]),
    BrowserAnimationsModule
  ],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AuthorizeInterceptor, multi: true },
    RoleService
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

RobinDBL
  • 9
  • 2

1 Answers1

0

Well yes, that's because the parent has the guard.

Angular needs to check if you can access the profile page, then check if you can access the orders page.

MGX
  • 2,534
  • 2
  • 14
  • I have both a `/orders` as well as a `/admin/orders` route. the `/orders` should be accessible by anyone that is logged in. the `/admin/orders` should only be accessible by admins – RobinDBL Oct 05 '22 at 08:02
  • Well your routes don't reflect what you're saying actually – MGX Oct 05 '22 at 08:55