├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── app │ ├── _guards │ │ ├── auth.guard.ts │ │ └── index.ts │ ├── _helpers │ │ ├── error.interceptor.ts │ │ ├── fake-backend.ts │ │ ├── index.ts │ │ └── jwt.interceptor.ts │ ├── _models │ │ ├── index.ts │ │ ├── role.ts │ │ └── user.ts │ ├── _services │ │ ├── authentication.service.ts │ │ ├── index.ts │ │ └── user.service.ts │ ├── admin │ │ ├── admin.component.html │ │ ├── admin.component.ts │ │ └── index.ts │ ├── app.component.html │ ├── app.component.ts │ ├── app.module.ts │ ├── app.routing.ts │ ├── home │ │ ├── home.component.html │ │ ├── home.component.ts │ │ └── index.ts │ └── login │ │ ├── index.ts │ │ ├── login.component.html │ │ └── login.component.ts ├── index.html ├── main.ts ├── polyfills.ts └── typings.d.ts ├── tsconfig.json └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | typings 33 | 34 | # Optional npm cache directory 35 | .npm 36 | 37 | # Optional REPL history 38 | .node_repl_history 39 | 40 | # Generated files 41 | dist -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Jason Watmore 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-7-role-based-authorization-example 2 | 3 | Angular 7 - Role Based Authorization Example with Webpack 4 4 | 5 | To see a demo and further details go to http://jasonwatmore.com/post/2018/11/22/angular-7-role-based-authorization-tutorial-with-example -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-7-role-based-authorization-example", 3 | "version": "1.0.0", 4 | "repository": { 5 | "type": "git", 6 | "url": "https://github.com/cornflourblue/angular-7-role-based-authorization-example.git" 7 | }, 8 | "scripts": { 9 | "build": "webpack --mode production", 10 | "start": "webpack-dev-server --mode development --open" 11 | }, 12 | "license": "MIT", 13 | "dependencies": { 14 | "@angular/common": "^7.1.0", 15 | "@angular/compiler": "^7.1.0", 16 | "@angular/core": "^7.1.0", 17 | "@angular/forms": "^7.1.0", 18 | "@angular/platform-browser": "^7.1.0", 19 | "@angular/platform-browser-dynamic": "^7.1.0", 20 | "@angular/router": "^7.1.0", 21 | "core-js": "^2.5.7", 22 | "rxjs": "^6.3.3", 23 | "zone.js": "^0.8.26" 24 | }, 25 | "devDependencies": { 26 | "@types/node": "^10.12.2", 27 | "angular2-template-loader": "^0.6.2", 28 | "html-webpack-plugin": "^3.2.0", 29 | "raw-loader": "^1.0.0", 30 | "ts-loader": "^5.2.2", 31 | "typescript": "^3.1.3", 32 | "webpack": "^4.24.0", 33 | "webpack-cli": "^3.1.2", 34 | "webpack-dev-server": "^3.1.14" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/app/_guards/auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; 3 | 4 | import { AuthenticationService } from '@/_services'; 5 | 6 | @Injectable({ providedIn: 'root' }) 7 | export class AuthGuard implements CanActivate { 8 | constructor( 9 | private router: Router, 10 | private authenticationService: AuthenticationService 11 | ) { } 12 | 13 | canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { 14 | const currentUser = this.authenticationService.currentUserValue; 15 | if (currentUser) { 16 | // check if route is restricted by role 17 | if (route.data.roles && route.data.roles.indexOf(currentUser.role) === -1) { 18 | // role not authorised so redirect to home page 19 | this.router.navigate(['/']); 20 | return false; 21 | } 22 | 23 | // authorised so return true 24 | return true; 25 | } 26 | 27 | // not logged in so redirect to login page with the return url 28 | this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } }); 29 | return false; 30 | } 31 | } -------------------------------------------------------------------------------- /src/app/_guards/index.ts: -------------------------------------------------------------------------------- 1 | export * from './auth.guard'; -------------------------------------------------------------------------------- /src/app/_helpers/error.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; 3 | import { Observable, throwError } from 'rxjs'; 4 | import { catchError } from 'rxjs/operators'; 5 | 6 | import { AuthenticationService } from '@/_services'; 7 | 8 | @Injectable() 9 | export class ErrorInterceptor implements HttpInterceptor { 10 | constructor(private authenticationService: AuthenticationService) { } 11 | 12 | intercept(request: HttpRequest, next: HttpHandler): Observable> { 13 | return next.handle(request).pipe(catchError(err => { 14 | if ([401, 403].indexOf(err.status) !== -1) { 15 | // auto logout if 401 Unauthorized or 403 Forbidden response returned from api 16 | this.authenticationService.logout(); 17 | location.reload(true); 18 | } 19 | 20 | const error = err.error.message || err.statusText; 21 | return throwError(error); 22 | })) 23 | } 24 | } -------------------------------------------------------------------------------- /src/app/_helpers/fake-backend.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS } from '@angular/common/http'; 3 | import { Observable, of, throwError } from 'rxjs'; 4 | import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators'; 5 | 6 | import { User, Role } from '@/_models'; 7 | 8 | @Injectable() 9 | export class FakeBackendInterceptor implements HttpInterceptor { 10 | intercept(request: HttpRequest, next: HttpHandler): Observable> { 11 | const users: User[] = [ 12 | { id: 1, username: 'admin', password: 'admin', firstName: 'Admin', lastName: 'User', role: Role.Admin }, 13 | { id: 2, username: 'user', password: 'user', firstName: 'Normal', lastName: 'User', role: Role.User } 14 | ]; 15 | 16 | const authHeader = request.headers.get('Authorization'); 17 | const isLoggedIn = authHeader && authHeader.startsWith('Bearer fake-jwt-token'); 18 | const roleString = isLoggedIn && authHeader.split('.')[1]; 19 | const role = roleString ? Role[roleString] : null; 20 | 21 | // wrap in delayed observable to simulate server api call 22 | return of(null).pipe(mergeMap(() => { 23 | 24 | // authenticate - public 25 | if (request.url.endsWith('/users/authenticate') && request.method === 'POST') { 26 | const user = users.find(x => x.username === request.body.username && x.password === request.body.password); 27 | if (!user) return error('Username or password is incorrect'); 28 | return ok({ 29 | id: user.id, 30 | username: user.username, 31 | firstName: user.firstName, 32 | lastName: user.lastName, 33 | role: user.role, 34 | token: `fake-jwt-token.${user.role}` 35 | }); 36 | } 37 | 38 | // get user by id - admin or user (user can only access their own record) 39 | if (request.url.match(/\/users\/\d+$/) && request.method === 'GET') { 40 | if (!isLoggedIn) return unauthorised(); 41 | 42 | // get id from request url 43 | let urlParts = request.url.split('/'); 44 | let id = parseInt(urlParts[urlParts.length - 1]); 45 | 46 | // only allow normal users access to their own record 47 | const currentUser = users.find(x => x.role === role); 48 | if (id !== currentUser.id && role !== Role.Admin) return unauthorised(); 49 | 50 | const user = users.find(x => x.id === id); 51 | return ok(user); 52 | } 53 | 54 | // get all users (admin only) 55 | if (request.url.endsWith('/users') && request.method === 'GET') { 56 | if (role !== Role.Admin) return unauthorised(); 57 | return ok(users); 58 | } 59 | 60 | // pass through any requests not handled above 61 | return next.handle(request); 62 | })) 63 | // call materialize and dematerialize to ensure delay even if an error is thrown (https://github.com/Reactive-Extensions/RxJS/issues/648) 64 | .pipe(materialize()) 65 | .pipe(delay(500)) 66 | .pipe(dematerialize()); 67 | 68 | // private helper functions 69 | 70 | function ok(body) { 71 | return of(new HttpResponse({ status: 200, body })); 72 | } 73 | 74 | function unauthorised() { 75 | return throwError({ status: 401, error: { message: 'Unauthorised' } }); 76 | } 77 | 78 | function error(message) { 79 | return throwError({ status: 400, error: { message } }); 80 | } 81 | } 82 | } 83 | 84 | export let fakeBackendProvider = { 85 | // use fake backend in place of Http service for backend-less development 86 | provide: HTTP_INTERCEPTORS, 87 | useClass: FakeBackendInterceptor, 88 | multi: true 89 | }; -------------------------------------------------------------------------------- /src/app/_helpers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './error.interceptor'; 2 | export * from './jwt.interceptor'; 3 | export * from './fake-backend'; -------------------------------------------------------------------------------- /src/app/_helpers/jwt.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; 3 | import { Observable } from 'rxjs'; 4 | 5 | import { AuthenticationService } from '@/_services'; 6 | 7 | @Injectable() 8 | export class JwtInterceptor implements HttpInterceptor { 9 | constructor(private authenticationService: AuthenticationService) { } 10 | 11 | intercept(request: HttpRequest, next: HttpHandler): Observable> { 12 | // add authorization header with jwt token if available 13 | let currentUser = this.authenticationService.currentUserValue; 14 | if (currentUser && currentUser.token) { 15 | request = request.clone({ 16 | setHeaders: { 17 | Authorization: `Bearer ${currentUser.token}` 18 | } 19 | }); 20 | } 21 | 22 | return next.handle(request); 23 | } 24 | } -------------------------------------------------------------------------------- /src/app/_models/index.ts: -------------------------------------------------------------------------------- 1 | export * from './role'; 2 | export * from './user'; -------------------------------------------------------------------------------- /src/app/_models/role.ts: -------------------------------------------------------------------------------- 1 | export enum Role { 2 | User = 'User', 3 | Admin = 'Admin' 4 | } -------------------------------------------------------------------------------- /src/app/_models/user.ts: -------------------------------------------------------------------------------- 1 | import { Role } from "./role"; 2 | 3 | export class User { 4 | id: number; 5 | username: string; 6 | password: string; 7 | firstName: string; 8 | lastName: string; 9 | role: Role; 10 | token?: string; 11 | } -------------------------------------------------------------------------------- /src/app/_services/authentication.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { BehaviorSubject, Observable } from 'rxjs'; 4 | import { map } from 'rxjs/operators'; 5 | 6 | import { User } from '@/_models'; 7 | 8 | @Injectable({ providedIn: 'root' }) 9 | export class AuthenticationService { 10 | private currentUserSubject: BehaviorSubject; 11 | public currentUser: Observable; 12 | 13 | constructor(private http: HttpClient) { 14 | this.currentUserSubject = new BehaviorSubject(JSON.parse(localStorage.getItem('currentUser'))); 15 | this.currentUser = this.currentUserSubject.asObservable(); 16 | } 17 | 18 | public get currentUserValue(): User { 19 | return this.currentUserSubject.value; 20 | } 21 | 22 | login(username: string, password: string) { 23 | return this.http.post(`${config.apiUrl}/users/authenticate`, { username, password }) 24 | .pipe(map(user => { 25 | // login successful if there's a jwt token in the response 26 | if (user && user.token) { 27 | // store user details and jwt token in local storage to keep user logged in between page refreshes 28 | localStorage.setItem('currentUser', JSON.stringify(user)); 29 | this.currentUserSubject.next(user); 30 | } 31 | 32 | return user; 33 | })); 34 | } 35 | 36 | logout() { 37 | // remove user from local storage to log user out 38 | localStorage.removeItem('currentUser'); 39 | this.currentUserSubject.next(null); 40 | } 41 | } -------------------------------------------------------------------------------- /src/app/_services/index.ts: -------------------------------------------------------------------------------- 1 | export * from './authentication.service'; 2 | export * from './user.service'; -------------------------------------------------------------------------------- /src/app/_services/user.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | 4 | import { User } from '@/_models'; 5 | 6 | @Injectable({ providedIn: 'root' }) 7 | export class UserService { 8 | constructor(private http: HttpClient) { } 9 | 10 | getAll() { 11 | return this.http.get(`${config.apiUrl}/users`); 12 | } 13 | 14 | getById(id: number) { 15 | return this.http.get(`${config.apiUrl}/users/${id}`); 16 | } 17 | } -------------------------------------------------------------------------------- /src/app/admin/admin.component.html: -------------------------------------------------------------------------------- 1 | 

Admin

2 |

This page can only be accessed by administrators.

3 |
4 | All users from secure (admin only) api end point: 5 |
    6 |
  • {{user.firstName}} {{user.lastName}}
  • 7 |
8 |
-------------------------------------------------------------------------------- /src/app/admin/admin.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { first } from 'rxjs/operators'; 3 | 4 | import { User } from '@/_models'; 5 | import { UserService } from '@/_services'; 6 | 7 | @Component({ templateUrl: 'admin.component.html' }) 8 | export class AdminComponent implements OnInit { 9 | users: User[] = []; 10 | 11 | constructor(private userService: UserService) { } 12 | 13 | ngOnInit() { 14 | this.userService.getAll().pipe(first()).subscribe(users => { 15 | this.users = users; 16 | }); 17 | } 18 | } -------------------------------------------------------------------------------- /src/app/admin/index.ts: -------------------------------------------------------------------------------- 1 | export * from './admin.component'; -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 |  2 | 9 | 10 | 11 |
12 |
13 |
14 |
15 | 16 |
17 |
18 |
19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | 4 | import { AuthenticationService } from './_services'; 5 | import { User, Role } from './_models'; 6 | 7 | @Component({ selector: 'app', templateUrl: 'app.component.html' }) 8 | export class AppComponent { 9 | currentUser: User; 10 | 11 | constructor( 12 | private router: Router, 13 | private authenticationService: AuthenticationService 14 | ) { 15 | this.authenticationService.currentUser.subscribe(x => this.currentUser = x); 16 | } 17 | 18 | get isAdmin() { 19 | return this.currentUser && this.currentUser.role === Role.Admin; 20 | } 21 | 22 | logout() { 23 | this.authenticationService.logout(); 24 | this.router.navigate(['/login']); 25 | } 26 | } -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { ReactiveFormsModule } from '@angular/forms'; 4 | import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; 5 | 6 | // used to create fake backend 7 | import { fakeBackendProvider } from './_helpers'; 8 | 9 | import { AppComponent } from './app.component'; 10 | import { routing } from './app.routing'; 11 | 12 | import { JwtInterceptor, ErrorInterceptor } from './_helpers'; 13 | import { HomeComponent } from './home'; 14 | import { AdminComponent } from './admin'; 15 | import { LoginComponent } from './login'; 16 | 17 | @NgModule({ 18 | imports: [ 19 | BrowserModule, 20 | ReactiveFormsModule, 21 | HttpClientModule, 22 | routing 23 | ], 24 | declarations: [ 25 | AppComponent, 26 | HomeComponent, 27 | AdminComponent, 28 | LoginComponent 29 | ], 30 | providers: [ 31 | { provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true }, 32 | { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true }, 33 | 34 | // provider used to create fake backend 35 | fakeBackendProvider 36 | ], 37 | bootstrap: [AppComponent] 38 | }) 39 | 40 | export class AppModule { } -------------------------------------------------------------------------------- /src/app/app.routing.ts: -------------------------------------------------------------------------------- 1 | import { Routes, RouterModule } from '@angular/router'; 2 | 3 | import { HomeComponent } from './home'; 4 | import { AdminComponent } from './admin'; 5 | import { LoginComponent } from './login'; 6 | import { AuthGuard } from './_guards'; 7 | import { Role } from './_models'; 8 | 9 | const appRoutes: Routes = [ 10 | { 11 | path: '', 12 | component: HomeComponent, 13 | canActivate: [AuthGuard] 14 | }, 15 | { 16 | path: 'admin', 17 | component: AdminComponent, 18 | canActivate: [AuthGuard], 19 | data: { roles: [Role.Admin] } 20 | }, 21 | { 22 | path: 'login', 23 | component: LoginComponent 24 | }, 25 | 26 | // otherwise redirect to home 27 | { path: '**', redirectTo: '' } 28 | ]; 29 | 30 | export const routing = RouterModule.forRoot(appRoutes); -------------------------------------------------------------------------------- /src/app/home/home.component.html: -------------------------------------------------------------------------------- 1 | 

Home

2 |

You're logged in with Angular 7 & JWT!!

3 |

Your role is: {{currentUser.role}}.

4 |

This page can be accessed by all authenticated users.

5 |
6 | Current user from secure api end point: 7 |
    8 |
  • {{userFromApi.firstName}} {{userFromApi.lastName}}
  • 9 |
10 |
-------------------------------------------------------------------------------- /src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { first } from 'rxjs/operators'; 3 | 4 | import { User } from '@/_models'; 5 | import { UserService, AuthenticationService } from '@/_services'; 6 | 7 | @Component({ templateUrl: 'home.component.html' }) 8 | export class HomeComponent { 9 | currentUser: User; 10 | userFromApi: User; 11 | 12 | constructor( 13 | private userService: UserService, 14 | private authenticationService: AuthenticationService 15 | ) { 16 | this.currentUser = this.authenticationService.currentUserValue; 17 | } 18 | 19 | ngOnInit() { 20 | this.userService.getById(this.currentUser.id).pipe(first()).subscribe(user => { 21 | this.userFromApi = user; 22 | }); 23 | } 24 | } -------------------------------------------------------------------------------- /src/app/home/index.ts: -------------------------------------------------------------------------------- 1 | export * from './home.component'; -------------------------------------------------------------------------------- /src/app/login/index.ts: -------------------------------------------------------------------------------- 1 | export * from './login.component'; -------------------------------------------------------------------------------- /src/app/login/login.component.html: -------------------------------------------------------------------------------- 1 | 
2 | Normal User - U: user P: user
3 | Administrator - U: admin P: admin 4 |
5 |

Login

6 |
7 |
8 | 9 | 10 |
11 |
Username is required
12 |
13 |
14 |
15 | 16 | 17 |
18 |
Password is required
19 |
20 |
21 |
22 | 23 | 24 |
25 |
{{error}}
26 |
-------------------------------------------------------------------------------- /src/app/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router, ActivatedRoute } from '@angular/router'; 3 | import { FormBuilder, FormGroup, Validators } from '@angular/forms'; 4 | import { first } from 'rxjs/operators'; 5 | 6 | import { AuthenticationService } from '@/_services'; 7 | 8 | @Component({ templateUrl: 'login.component.html' }) 9 | export class LoginComponent implements OnInit { 10 | loginForm: FormGroup; 11 | loading = false; 12 | submitted = false; 13 | returnUrl: string; 14 | error = ''; 15 | 16 | constructor( 17 | private formBuilder: FormBuilder, 18 | private route: ActivatedRoute, 19 | private router: Router, 20 | private authenticationService: AuthenticationService 21 | ) { 22 | // redirect to home if already logged in 23 | if (this.authenticationService.currentUserValue) { 24 | this.router.navigate(['/']); 25 | } 26 | } 27 | 28 | ngOnInit() { 29 | this.loginForm = this.formBuilder.group({ 30 | username: ['', Validators.required], 31 | password: ['', Validators.required] 32 | }); 33 | 34 | // get return url from route parameters or default to '/' 35 | this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/'; 36 | } 37 | 38 | // convenience getter for easy access to form fields 39 | get f() { return this.loginForm.controls; } 40 | 41 | onSubmit() { 42 | this.submitted = true; 43 | 44 | // stop here if form is invalid 45 | if (this.loginForm.invalid) { 46 | return; 47 | } 48 | 49 | this.loading = true; 50 | this.authenticationService.login(this.f.username.value, this.f.password.value) 51 | .pipe(first()) 52 | .subscribe( 53 | data => { 54 | this.router.navigate([this.returnUrl]); 55 | }, 56 | error => { 57 | this.error = error; 58 | this.loading = false; 59 | }); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Angular 7 - Role Based Authorization Tutorial & Example 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | Loading... 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import './polyfills'; 2 | 3 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 4 | import { AppModule } from './app/app.module'; 5 | platformBrowserDynamic().bootstrapModule(AppModule); -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | import 'core-js/es6/reflect'; 2 | import 'core-js/es7/reflect'; 3 | import 'zone.js/dist/zone'; -------------------------------------------------------------------------------- /src/typings.d.ts: -------------------------------------------------------------------------------- 1 | // so the typescript compiler doesn't complain about the global config object 2 | declare var config: any; -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "emitDecoratorMetadata": true, 4 | "experimentalDecorators": true, 5 | "lib": [ 6 | "es2015", 7 | "dom" 8 | ], 9 | "module": "commonjs", 10 | "moduleResolution": "node", 11 | "noImplicitAny": false, 12 | "sourceMap": true, 13 | "suppressImplicitAnyIndexErrors": true, 14 | "target": "es5", 15 | "baseUrl": "src", 16 | "paths": { 17 | "@/*": [ 18 | "app/*" 19 | ] 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const path = require('path'); 4 | 5 | module.exports = { 6 | entry: './src/main.ts', 7 | module: { 8 | rules: [ 9 | { 10 | test: /\.ts$/, 11 | use: ['ts-loader', 'angular2-template-loader'], 12 | exclude: /node_modules/ 13 | }, 14 | { 15 | test: /\.(html|css)$/, 16 | loader: 'raw-loader' 17 | }, 18 | ] 19 | }, 20 | resolve: { 21 | extensions: ['.ts', '.js'], 22 | alias: { 23 | '@': path.resolve(__dirname, 'src/app/'), 24 | } 25 | }, 26 | plugins: [ 27 | new HtmlWebpackPlugin({ 28 | template: './src/index.html', 29 | filename: 'index.html', 30 | inject: 'body' 31 | }), 32 | new webpack.DefinePlugin({ 33 | // global app config object 34 | config: JSON.stringify({ 35 | apiUrl: 'http://localhost:4000' 36 | }) 37 | }) 38 | ], 39 | optimization: { 40 | splitChunks: { 41 | chunks: 'all', 42 | }, 43 | runtimeChunk: true 44 | }, 45 | devServer: { 46 | historyApiFallback: true 47 | } 48 | }; --------------------------------------------------------------------------------