Route Guard
MODIFY
angular.json
angular.json
"src/assets"
],
"styles": [
- "src/styles.scss"
+ "src/styles.scss",
+ "./node_modules/angular2-toaster/src/toaster.scss"
],
"scripts": [
"./node_modules/hammerjs/hammer.min.js"
"src/assets"
],
"styles": [
- "src/styles.scss"
+ "src/styles.scss",
+ "./node_modules/angular2-toaster/src/toaster.scss"
],
"scripts": []
}

MODIFY
package.json
package.json
"@angular/platform-browser": "~8.2.0",
"@angular/platform-browser-dynamic": "~8.2.0",
"@angular/router": "~8.2.0",
+ "angular2-toaster": "^8.0.0",
"hammerjs": "^2.0.8",
"keycloak-admin": "^1.13.0",
"keycloak-angular": "^7.0.1",

MODIFY
src/app/app-routing.module.ts
src/app/app-routing.module.ts
@@ -4,12 +4,20 @@ import { AdminComponent } from './admin/admin.component';
import { DeveloperComponent } from './developer/developer.component';
import { CreateDeveloperComponent } from './admin/create-developer/create-developer.component';
import { EditDeveloperComponent } from './admin/edit-developer/edit-developer.component';
+import { DevportalGuard } from './auth/devportal.guard';
+import { AdminGuard } from './auth/admin.guard';
+import {NotAuthorizedComponent} from './not-authorized/not-authorized.component';
const routes: Routes = [
- { path: '', component: DeveloperComponent },
- { path: 'admin', component: AdminComponent },
- { path: 'admin/create/developer', component: CreateDeveloperComponent },
- { path: 'admin/edit/developer/:developerId', component: EditDeveloperComponent}
+ { path: '', component: DeveloperComponent, canActivate: [DevportalGuard] },
+ { path: 'admin',
+ component: AdminComponent,
+ canActivate: [AdminGuard],
+ children: []
+ },
+ { path: 'admin/create/developer', component: CreateDeveloperComponent, canActivate: [AdminGuard] },
+ { path: 'admin/edit/developer/:developerId', component: EditDeveloperComponent, canActivate: [AdminGuard] },
+ { path: 'not-authorized', component: NotAuthorizedComponent }
];
@NgModule({

MODIFY
src/app/app.component.html
src/app/app.component.html
<div id="menu-spacer"></div>
+
+
<div class="router-outlet-wrapper">
+ <toaster-container [style]=""></toaster-container>
<router-outlet></router-outlet>
</div>

MODIFY
src/app/app.component.scss
src/app/app.component.scss
+@import '../../node_modules/angular2-toaster/src/toaster';
+
.router-outlet-wrapper {
padding-left: 110px;
padding-top: 70px;
+ padding-right: 40px;
}
#pas-header {
width: 75px;
box-shadow: 0px 1px 1px 2px rgba(230,230,230,1);
}
+
+:host ::ng-deep #toast-container {
+ margin-top: 70px;
+}

MODIFY
src/app/app.module.ts
src/app/app.module.ts
@@ -26,6 +26,8 @@ import { ClientMappingComponent } from './admin/create-developer/client-mapping.
import { DragDropModule } from '@angular/cdk/drag-drop';
import { MatButtonModule, MatInputModule } from '@angular/material';
import { EditDeveloperComponent } from './admin/edit-developer/edit-developer.component';
+import { NotAuthorizedComponent } from './not-authorized/not-authorized.component';
+import { ToasterModule } from 'angular2-toaster';
@NgModule({
@@ -38,7 +40,8 @@ import { EditDeveloperComponent } from './admin/edit-developer/edit-developer.co
DeveloperListComponent,
CreateDeveloperComponent,
ClientMappingComponent,
- EditDeveloperComponent
+ EditDeveloperComponent,
+ NotAuthorizedComponent
],
imports: [
BrowserModule,
@@ -52,7 +55,8 @@ import { EditDeveloperComponent } from './admin/edit-developer/edit-developer.co
ReactiveFormsModule,
DragDropModule,
MatButtonModule,
- MatInputModule
+ MatInputModule,
+ ToasterModule.forRoot(),
],
providers: [
{

ADD
src/app/auth/admin.guard.spec.ts
+import { TestBed, async, inject } from '@angular/core/testing';
+
+import { AdminGuard } from './admin.guard';
+
+describe('AdminGuard', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [AdminGuard]
+ });
+ });
+
+ it('should ...', inject([AdminGuard], (guard: AdminGuard) => {
+ expect(guard).toBeTruthy();
+ }));
+});

ADD
src/app/auth/admin.guard.ts
+import { Injectable } from '@angular/core';
+import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from '@angular/router';
+import { Observable } from 'rxjs';
+import {KeycloakAuthGuard, KeycloakService} from 'keycloak-angular';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class AdminGuard extends KeycloakAuthGuard implements CanActivate {
+
+ constructor(protected router: Router, protected keycloakAngular: KeycloakService) {
+ super(router, keycloakAngular);
+ }
+
+ isAccessAllowed(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
+ const keycloakInstance = this.keycloakAngular.getKeycloakInstance();
+ const isAuthorized = keycloakInstance.tokenParsed.realm_access.roles.find((role) => role === 'apiadmin') !== undefined;
+ if (!isAuthorized) {
+ this.router.navigate(['/not-authorized'], { skipLocationChange: true });
+ }
+ return Promise.resolve(isAuthorized);
+ }
+
+}

ADD
src/app/auth/devportal.guard.spec.ts
+import { TestBed, async, inject } from '@angular/core/testing';
+
+import { DevportalGuard } from './devportal.guard';
+
+describe('DevportalGuard', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [DevportalGuard]
+ });
+ });
+
+ it('should ...', inject([DevportalGuard], (guard: DevportalGuard) => {
+ expect(guard).toBeTruthy();
+ }));
+});

ADD
src/app/auth/devportal.guard.ts
+import { Injectable } from '@angular/core';
+import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
+import { KeycloakAuthGuard, KeycloakService } from 'keycloak-angular';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class DevportalGuard extends KeycloakAuthGuard implements CanActivate {
+ constructor(protected router: Router, protected keycloakAngular: KeycloakService) {
+ super(router, keycloakAngular);
+ }
+
+ isAccessAllowed(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
+ const keycloakInstance = this.keycloakAngular.getKeycloakInstance();
+ const isAuthorized = keycloakInstance.tokenParsed.realm_access.roles.find((role) => role === 'devportaluser') !== undefined;
+ if (!isAuthorized) {
+ this.router.navigate(['/not-authorized'], { skipLocationChange: true });
+ }
+ return Promise.resolve(isAuthorized);
+ }
+}

ADD
src/app/not-authorized/not-authorized.component.html
+

ADD
src/app/not-authorized/not-authorized.component.scss
src/app/not-authorized/not-authorized.component.scss
ADD
src/app/not-authorized/not-authorized.component.spec.ts
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { NotAuthorizedComponent } from './not-authorized.component';
+
+describe('NotAuthorizedComponent', () => {
+ let component: NotAuthorizedComponent;
+ let fixture: ComponentFixture<NotAuthorizedComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ NotAuthorizedComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(NotAuthorizedComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});

ADD
src/app/not-authorized/not-authorized.component.ts
+import { Component, OnInit } from '@angular/core';
+import { Toast, ToasterContainerComponent, ToasterService } from 'angular2-toaster';
+
+@Component({
+ selector: 'app-not-authorized',
+ templateUrl: './not-authorized.component.html',
+ styleUrls: ['./not-authorized.component.scss']
+})
+export class NotAuthorizedComponent implements OnInit {
+
+ constructor(private toasterService: ToasterService) { }
+
+ ngOnInit() {
+ const toast: Toast = {
+ type: 'warning',
+ body: 'You are not authorized to see this page.',
+ timeout: 0,
+ showCloseButton: true
+ };
+ this.toasterService.pop(toast);
+ }
+
+}

MODIFY
src/app/pas-header/pas-header.component.ts
src/app/pas-header/pas-header.component.ts
import { Component, OnInit } from '@angular/core';
import { KeycloakService } from 'keycloak-angular';
+import {ActivatedRoute, Router} from '@angular/router';
@Component({
selector: 'app-pas-header',
@@ -10,12 +11,15 @@ export class PasHeaderComponent {
public user: string = this.keycloak.getKeycloakInstance().profile.username;
- constructor(private keycloak: KeycloakService) { }
+ constructor(private keycloak: KeycloakService, private router: Router, private route: ActivatedRoute) { }
public logout() {
+ const firstChild = this.route;
sessionStorage.setItem('apiman_keycloak_token', '');
sessionStorage.setItem('apiman_keycloak_refresh_token', '');
- this.keycloak.getKeycloakInstance().logout();
+ this.keycloak.getKeycloakInstance().logout({
+ redirectUri: location.href
+ });
}
}

GW-263: Route Guard