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 { }