The tutorial is Part 3 of the series: Angular Spring Boot JWT Authentication example | Angular 6 + Spring Security + MySQL Full Stack. Today we’re gonna build a Angular HTTP Client App that can interact with SpringBoot JWT Authentication Server.
Part 1: Overview and Architecture.
Part 2: Build SpringBoot Backend
Related Posts:
– Angular 6 Http Interceptor – with Node.js RestAPIs
– Angular 6 HttpClient – Get/Post/Put/Delete requests + SpringBoot RestAPIs + Bootstrap 4
Contents
How to build JWT Authentication frontend with Angular
Demo
Send Requests to Server
Add Token to Header with HttpInterceptor
We use Angular HttpInterceptor
with intercept()
method to inspect and transform HTTP requests (before they are sent to server):
import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http'; const TOKEN_HEADER_KEY = 'Authorization'; @Injectable() export class AuthInterceptor implements HttpInterceptor { ... intercept(req: HttpRequest<any>, next: HttpHandler) { let authReq = req; const token = ...; if (token != null) { authReq = req.clone({ headers: req.headers.set(TOKEN_HEADER_KEY, 'Bearer ' + token) }); } return next.handle(authReq); } } export const httpInterceptorProviders = [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true } ]; |
– The HTTPRequest
object will be inspected and forwarded to handle()
method of the HttpHandler
object.
– handle()
method transforms HTTPRequest
object into an Observable
of HttpEvents
which includes the server’s response.
What is next: HttpHandler
object?
-> This object represents the next interceptor
in the chain of interceptor
s. The final ‘next’ in the chain is the Angular HttpClient
handler.
Angular 6 Http Interceptor – with Node.js RestAPIs
HTTP Request using HttpClient
We send HTTP Requests (signin/signup) using Angular HttpClient
:
import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs'; const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }; export class AuthService { private loginUrl = 'http://localhost:8080/api/auth/signin'; private signupUrl = 'http://localhost:8080/api/auth/signup'; constructor(private http: HttpClient) { } // JwtResponse(accessToken,type,username,authorities) attemptAuth(credentials: AuthLoginInfo): Observable<JwtResponse> { return this.http.post<JwtResponse>(this.loginUrl, credentials, httpOptions); } // SignUpInfo(name,username,email,role,password) signUp(info: SignUpInfo): Observable<string> { return this.http.post<string>(this.signupUrl, info, httpOptions); } } |
AuthLoginInfo
fields & SignUpInfo
fields are validated using Angular template-driven Form.
Angular 6 Form Validation example – Template-driven Forms
Once Token is saved, we can access protected resources simply:
export class UserService { private userUrl = 'http://localhost:8080/api/test/user'; private pmUrl = 'http://localhost:8080/api/test/pm'; private adminUrl = 'http://localhost:8080/api/test/admin'; constructor(private http: HttpClient) { } getUserBoard(): Observable<string> { return this.http.get(this.userUrl, { responseType: 'text' }); } getPMBoard(): Observable<string> { return this.http.get(this.pmUrl, { responseType: 'text' }); } getAdminBoard(): Observable<string> { return this.http.get(this.adminUrl, { responseType: 'text' }); } } |
Handle Responses
Using AuthService
to work with Observable
object:
Signup Response
export class RegisterComponent implements OnInit { ... constructor(private authService: AuthService) { } onSubmit() { ... this.authService.signUp(this.signupInfo).subscribe( data => { ... }, error => { ... } ); } } |
Login Response
In addition to using AuthService
to work with Observable
object, we also call TokenStorageService
methods to save Token, Username, Authorities:
export class LoginComponent implements OnInit { ... constructor(private authService: AuthService, private tokenStorage: TokenStorageService) { } ngOnInit() { if (this.tokenStorage.getToken()) { this.isLoggedIn = true; this.roles = this.tokenStorage.getAuthorities(); } } onSubmit() { ... this.authService.attemptAuth(this.loginInfo).subscribe( data => { this.tokenStorage.saveToken(data.accessToken); this.tokenStorage.saveUsername(data.username); this.tokenStorage.saveAuthorities(data.authorities); this.roles = this.tokenStorage.getAuthorities(); ... reloadPage(); }, error => { ... } ); } } |
Manage Token & User Logout
We use TokenStorageService
to manage Token inside Browser’s sessionStorage
:
export class TokenStorageService { private roles: Array<string> = []; public saveToken(token: string) { window.sessionStorage.removeItem(TOKEN_KEY); window.sessionStorage.setItem(TOKEN_KEY, token); } public getToken(): string { return sessionStorage.getItem(TOKEN_KEY); } public saveUsername(username: string) { window.sessionStorage.removeItem(USERNAME_KEY); window.sessionStorage.setItem(USERNAME_KEY, username); } public getUsername(): string { return sessionStorage.getItem(USERNAME_KEY); } public saveAuthorities(authorities: string[]) { window.sessionStorage.removeItem(AUTHORITIES_KEY); window.sessionStorage.setItem(AUTHORITIES_KEY, JSON.stringify(authorities)); } public getAuthorities(): string[] { this.roles = []; if (sessionStorage.getItem(TOKEN_KEY)) { JSON.parse(sessionStorage.getItem(AUTHORITIES_KEY)).forEach(authority => { this.roles.push(authority.authority); }); } return this.roles; } } |
For Logout action, we only need to clear Browser’s sessionStorage
:
export class TokenStorageService { ... signOut() { window.sessionStorage.clear(); } } |
Angular Client for JWT Authentication Overview
Goal
We will build Angular Client which allows users to register, login account. And depending on the role of current User (user, pm or admin), this system accepts what he can access:
The diagram below show how our system handles User Registration and User Login processes:
Elements Overview
– app.component
is the parent component that contains routerLink
and router-outlet
for routing. It also has an authority
variable as the condition for displaying items on navigation bar.
– user.component
, pm.component
, admin.component
correspond to Angular Components for User Board, PM Board, Admin Board. Each Board uses user.service
to access authority data.
– register.component
contains User Registration form, submission of the form will call auth.service
.
– login.component
contains User Login form, submission of the form will call auth.service
and token-storage.service
.
– user.service
gets access to authority data from Server using Angular HttpClient
($http
service).
– auth.service
handles authentication and signup actions with Server using Angular HttpClient
($http
service).
– every HTTP request by $http
service will be inspected and transformed before being sent to the Server by auth-interceptor
(implements HttpInterceptor
).
– auth-interceptor
check and get Token from token-storage.service
to add the Token to Authorization Header of the HTTP Requests.
– token-storage.service
manages Token inside Browser’s sessionStorage
.
- Interceptor: Angular 6 Http Interceptor – with Node.js RestAPIs
- Routing: Angular 6 Routing/Navigation – with Angular Router Service
- Form Validation: Angular 6 Form Validation example – Template-driven Forms
- Angular 6 HttpClient example: Angular 6 HttpClient – Get/Post/Put/Delete requests + SpringBoot RestAPIs + Bootstrap 4
Technologies
– Angular 6
– RxJS 6
Project Structure
Practice
Create Services & Components
Run commands below:
– ng g s auth/auth
– ng g s auth/token-storage
– ng g s services/user
– ng g c login
– ng g c register
– ng g c home
– ng g c user
– ng g c pm
– ng g c admin
AppModule
app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { HttpClientModule } from '@angular/common/http'; import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { LoginComponent } from './login/login.component'; import { UserComponent } from './user/user.component'; import { RegisterComponent } from './register/register.component'; import { HomeComponent } from './home/home.component'; import { AdminComponent } from './admin/admin.component'; import { PmComponent } from './pm/pm.component'; import { httpInterceptorProviders } from './auth/auth-interceptor'; @NgModule({ declarations: [ AppComponent, LoginComponent, UserComponent, RegisterComponent, HomeComponent, AdminComponent, PmComponent ], imports: [ BrowserModule, AppRoutingModule, FormsModule, HttpClientModule ], providers: [httpInterceptorProviders], bootstrap: [AppComponent] }) export class AppModule { } |
Services
Auth Models
auth/login-info.ts
export class AuthLoginInfo { username: string; password: string; constructor(username: string, password: string) { this.username = username; this.password = password; } } |
auth/sigup-info.ts
export class SignUpInfo { name: string; username: string; email: string; role: string[]; password: string; constructor(name: string, username: string, email: string, password: string) { this.name = name; this.username = username; this.email = email; this.password = password; this.role = ['user']; } } |
auth/jwt-response.ts
export class JwtResponse { accessToken: string; type: string; username: string; authorities: string[]; } |
Auth Service
auth/auth.service.ts
import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs'; import { JwtResponse } from './jwt-response'; import { AuthLoginInfo } from './login-info'; import { SignUpInfo } from './signup-info'; const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }; @Injectable({ providedIn: 'root' }) export class AuthService { private loginUrl = 'http://localhost:8080/api/auth/signin'; private signupUrl = 'http://localhost:8080/api/auth/signup'; constructor(private http: HttpClient) { } attemptAuth(credentials: AuthLoginInfo): Observable<JwtResponse> { return this.http.post<JwtResponse>(this.loginUrl, credentials, httpOptions); } signUp(info: SignUpInfo): Observable<string> { return this.http.post<string>(this.signupUrl, info, httpOptions); } } |
Token Storage Service
auth/token-storage.service.ts
import { Injectable } from '@angular/core'; const TOKEN_KEY = 'AuthToken'; const USERNAME_KEY = 'AuthUsername'; const AUTHORITIES_KEY = 'AuthAuthorities'; @Injectable({ providedIn: 'root' }) export class TokenStorageService { private roles: Array<string> = []; constructor() { } signOut() { window.sessionStorage.clear(); } public saveToken(token: string) { window.sessionStorage.removeItem(TOKEN_KEY); window.sessionStorage.setItem(TOKEN_KEY, token); } public getToken(): string { return sessionStorage.getItem(TOKEN_KEY); } public saveUsername(username: string) { window.sessionStorage.removeItem(USERNAME_KEY); window.sessionStorage.setItem(USERNAME_KEY, username); } public getUsername(): string { return sessionStorage.getItem(USERNAME_KEY); } public saveAuthorities(authorities: string[]) { window.sessionStorage.removeItem(AUTHORITIES_KEY); window.sessionStorage.setItem(AUTHORITIES_KEY, JSON.stringify(authorities)); } public getAuthorities(): string[] { this.roles = []; if (sessionStorage.getItem(TOKEN_KEY)) { JSON.parse(sessionStorage.getItem(AUTHORITIES_KEY)).forEach(authority => { this.roles.push(authority.authority); }); } return this.roles; } } |
User Service
services/user.service.ts
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class UserService { private userUrl = 'http://localhost:8080/api/test/user'; private pmUrl = 'http://localhost:8080/api/test/pm'; private adminUrl = 'http://localhost:8080/api/test/admin'; constructor(private http: HttpClient) { } getUserBoard(): Observable<string> { return this.http.get(this.userUrl, { responseType: 'text' }); } getPMBoard(): Observable<string> { return this.http.get(this.pmUrl, { responseType: 'text' }); } getAdminBoard(): Observable<string> { return this.http.get(this.adminUrl, { responseType: 'text' }); } } |
HTTP Interceptor
auth/auth-interceptor.ts
import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http'; import { TokenStorageService } from './token-storage.service'; const TOKEN_HEADER_KEY = 'Authorization'; @Injectable() export class AuthInterceptor implements HttpInterceptor { constructor(private token: TokenStorageService) { } intercept(req: HttpRequest<any>, next: HttpHandler) { let authReq = req; const token = this.token.getToken(); if (token != null) { authReq = req.clone({ headers: req.headers.set(TOKEN_HEADER_KEY, 'Bearer ' + token) }); } return next.handle(authReq); } } export const httpInterceptorProviders = [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true } ]; |
Components
Home Component
home.component.ts
import { Component, OnInit } from '@angular/core'; import { TokenStorageService } from '../auth/token-storage.service'; @Component({ selector: 'app-home', templateUrl: './home.component.html', styleUrls: ['./home.component.css'] }) export class HomeComponent implements OnInit { info: any; constructor(private token: TokenStorageService) { } ngOnInit() { this.info = { token: this.token.getToken(), username: this.token.getUsername(), authorities: this.token.getAuthorities() }; } logout() { this.token.signOut(); window.location.reload(); } } |
home.component.html
<div *ngIf="info.token; else loggedOut"> <h5 class="text-primary">Your Information</h5> <p> <strong>Username:</strong> {{info.username}}<br/> <strong>Roles:</strong> {{info.authorities}}<br /> <strong>Token:</strong> {{info.token}}. </p> <button class="btn btn-secondary" (click)="logout()">Logout</button> </div> <ng-template #loggedOut> Please login. </ng-template> |
Login Component
login.component.ts
import { Component, OnInit } from '@angular/core'; import { AuthService } from '../auth/auth.service'; import { TokenStorageService } from '../auth/token-storage.service'; import { AuthLoginInfo } from '../auth/login-info'; @Component({ selector: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.css'] }) export class LoginComponent implements OnInit { form: any = {}; isLoggedIn = false; isLoginFailed = false; errorMessage = ''; roles: string[] = []; private loginInfo: AuthLoginInfo; constructor(private authService: AuthService, private tokenStorage: TokenStorageService) { } ngOnInit() { if (this.tokenStorage.getToken()) { this.isLoggedIn = true; this.roles = this.tokenStorage.getAuthorities(); } } onSubmit() { console.log(this.form); this.loginInfo = new AuthLoginInfo( this.form.username, this.form.password); this.authService.attemptAuth(this.loginInfo).subscribe( data => { this.tokenStorage.saveToken(data.accessToken); this.tokenStorage.saveUsername(data.username); this.tokenStorage.saveAuthorities(data.authorities); this.isLoginFailed = false; this.isLoggedIn = true; this.roles = this.tokenStorage.getAuthorities(); this.reloadPage(); }, error => { console.log(error); this.errorMessage = error.error.message; this.isLoginFailed = true; } ); } reloadPage() { window.location.reload(); } } |
login.component.html
<div *ngIf="isLoggedIn; else loggedOut"> Logged in as {{roles}}. </div> <ng-template #loggedOut> <div class="row col-sm-6" style="max-width:350px;"> <form name="form" (ngSubmit)="f.form.valid && onSubmit()" #f="ngForm" novalidate> <div class="form-group"> <label for="username">Username</label> <input type="text" class="form-control" name="username" [(ngModel)]="form.username" #username="ngModel" required /> <div *ngIf="f.submitted && username.invalid"> <div *ngIf="username.errors.required">Username is required</div> </div> </div> <div class="form-group"> <label for="password">Password</label> <input type="password" class="form-control" name="password" [(ngModel)]="form.password" #password="ngModel" required minlength="6" /> <div *ngIf="f.submitted && password.invalid"> <div *ngIf="password.errors.required">Password is required</div> <div *ngIf="password.errors.minlength">Password must be at least 6 characters</div> </div> </div> <div class="form-group"> <button class="btn btn-primary">Login</button> <div *ngIf="f.submitted && isLoginFailed" class="alert alert-danger"> Login failed: {{errorMessage}} </div> </div> </form> <hr /> <p>Don't have an account?</p> <a href="signup" class="btn btn-success">Sign Up</a> </div> </ng-template> |
Register Component
register.component.ts
import { Component, OnInit } from '@angular/core'; import { AuthService } from '../auth/auth.service'; import { SignUpInfo } from '../auth/signup-info'; @Component({ selector: 'app-register', templateUrl: './register.component.html', styleUrls: ['./register.component.css'] }) export class RegisterComponent implements OnInit { form: any = {}; signupInfo: SignUpInfo; isSignedUp = false; isSignUpFailed = false; errorMessage = ''; constructor(private authService: AuthService) { } ngOnInit() { } onSubmit() { console.log(this.form); this.signupInfo = new SignUpInfo( this.form.name, this.form.username, this.form.email, this.form.password); this.authService.signUp(this.signupInfo).subscribe( data => { console.log(data); this.isSignedUp = true; this.isSignUpFailed = false; }, error => { console.log(error); this.errorMessage = error.error.message; this.isSignUpFailed = true; } ); } } |
register.component.html
<div *ngIf="isSignedUp; else signupForm"> Your registration is successful. Please login! </div> <ng-template #signupForm> <div class="row col-sm-6" style="max-width:350px;"> <form name="form" (ngSubmit)="f.form.valid && onSubmit()" #f="ngForm" novalidate> <div class="form-group"> <label for="name">Your name</label> <input type="text" class="form-control" name="name" [(ngModel)]="form.name" #name="ngModel" required /> <div *ngIf="f.submitted && name.invalid"> <div *ngIf="name.errors.required">Name is required</div> </div> </div> <div class="form-group"> <label for="username">Username</label> <input type="text" class="form-control" name="username" [(ngModel)]="form.username" #username="ngModel" required /> <div *ngIf="f.submitted && username.invalid"> <div *ngIf="username.errors.required">Username is required</div> </div> </div> <div class="form-group"> <label for="email">Email</label> <input type="text" class="form-control" name="email" [(ngModel)]="form.email" #email="ngModel" required email /> <div *ngIf="f.submitted && email.invalid"> <div *ngIf="email.errors.required">Email is required</div> <div *ngIf="email.errors.email">Email must be a valid email address</div> </div> </div> <div class="form-group"> <label for="password">Password</label> <input type="password" class="form-control" name="password" [(ngModel)]="form.password" #password="ngModel" required minlength="6" /> <div *ngIf="f.submitted && password.invalid"> <div *ngIf="password.errors.required">Password is required</div> <div *ngIf="password.errors.minlength">Password must be at least 6 characters</div> </div> </div> <div class="form-group"> <button class="btn btn-primary">Register</button> <div *ngIf="f.submitted && isSignUpFailed" class="alert alert-warning"> Signup failed!<br/>{{errorMessage}} </div> </div> </form> </div> </ng-template> |
[UserRole] Components
user/pm/admin.component.html
<h4>Content from Server</h4> {{board}} {{errorMessage}} |
user.component.ts
import { Component, OnInit } from '@angular/core'; import { UserService } from '../services/user.service'; @Component({ selector: 'app-user', templateUrl: './user.component.html', styleUrls: ['./user.component.css'] }) export class UserComponent implements OnInit { board: string; errorMessage: string; constructor(private userService: UserService) { } ngOnInit() { this.userService.getUserBoard().subscribe( data => { this.board = data; }, error => { this.errorMessage = `${error.status}: ${JSON.parse(error.error).message}`; } ); } } |
pm.component.ts
import { Component, OnInit } from '@angular/core'; import { UserService } from '../services/user.service'; @Component({ selector: 'app-pm', templateUrl: './pm.component.html', styleUrls: ['./pm.component.css'] }) export class PmComponent implements OnInit { board: string; errorMessage: string; constructor(private userService: UserService) { } ngOnInit() { this.userService.getPMBoard().subscribe( data => { this.board = data; }, error => { this.errorMessage = `${error.status}: ${JSON.parse(error.error).message}`; } ); } } |
admin.component.ts
import { Component, OnInit } from '@angular/core'; import { UserService } from '../services/user.service'; @Component({ selector: 'app-admin', templateUrl: './admin.component.html', styleUrls: ['./admin.component.css'] }) export class AdminComponent implements OnInit { board: string; errorMessage: string; constructor(private userService: UserService) { } ngOnInit() { this.userService.getAdminBoard().subscribe( data => { this.board = data; }, error => { this.errorMessage = `${error.status}: ${JSON.parse(error.error).message}`; } ); } } |
App Routing
app-routing.module.ts
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { RegisterComponent } from './register/register.component'; import { LoginComponent } from './login/login.component'; import { HomeComponent } from './home/home.component'; import { UserComponent } from './user/user.component'; import { PmComponent } from './pm/pm.component'; import { AdminComponent } from './admin/admin.component'; const routes: Routes = [ { path: 'home', component: HomeComponent }, { path: 'user', component: UserComponent }, { path: 'pm', component: PmComponent }, { path: 'admin', component: AdminComponent }, { path: 'auth/login', component: LoginComponent }, { path: 'signup', component: RegisterComponent }, { path: '', redirectTo: 'home', pathMatch: 'full' } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } |
app.component.ts
import { Component, OnInit } from '@angular/core'; import { TokenStorageService } from './auth/token-storage.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { private roles: string[]; private authority: string; constructor(private tokenStorage: TokenStorageService) { } ngOnInit() { if (this.tokenStorage.getToken()) { this.roles = this.tokenStorage.getAuthorities(); this.roles.every(role => { if (role === 'ROLE_ADMIN') { this.authority = 'admin'; return false; } else if (role === 'ROLE_PM') { this.authority = 'pm'; return false; } this.authority = 'user'; return true; }); } } } |
app.component.html
<nav class="navbar navbar-inverse"> <div class="container-fluid"> <div class="navbar-header"> <a class="navbar-brand" href="#">grokonez</a> </div> <ul class="nav navbar-nav" routerLinkActive="active"> <li class="nav-item"><a class="nav-link" routerLink="home">Home</a></li> <li *ngIf="authority === 'user'" class="nav-item"> <a class="nav-link" routerLink="user">User Board</a> </li> <li *ngIf="authority === 'admin'" class="nav-item"> <a class="nav-link" routerLink="admin">Admin Board</a> </li> <li *ngIf="authority === 'pm'" class="nav-item"> <a class="nav-link" routerLink="pm">PM Board</a> </li> <li *ngIf="!authority" class="nav-item"> <a class="nav-link" routerLink="auth/login">Login</a> </li> </ul> </div> </nav> <div class="container"> <router-outlet></router-outlet> </div> |
SourceCode
Last updated on April 9, 2020.
Please help me, I am days trying to find the solution to this error I am from Brazil and my name is Everton:
I did not compreeend some post that I used to try to solve it, and I am using this project as a basis to develop login in my company (home oficce).
Kindness, help me …
HomeComponent_Host.ngfactory.js? [sm]:1 ERROR SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse ()
at TokenStorageService.push../src/app/auth/token-storage.service.ts.TokenStorageService.getAuthorities (token-storage.service.ts:45)
at HomeComponent.push../src/app/home/home.component.ts.HomeComponent.ngOnInit (home.component.ts:19)
at checkAndUpdateDirectiveInline (core.js:18620)
at checkAndUpdateNodeInline (core.js:19884)
at checkAndUpdateNode (core.js:19846)
at debugCheckAndUpdateNode (core.js:20480)
at debugCheckDirectivesFn (core.js:20440)
at Object.eval [as updateDirectives] (HomeComponent_Host.ngfactory.js? [sm]:1)
at Object.debugUpdateDirectives [as updateDirectives] (core.js:20432)
View_HomeComponent_Host_0 @ HomeComponent_Host.ngfactory.js? [sm]:1
proxyClass @ compiler.js:17129
push../node_modules/@angular/core/fesm5/core.js.DebugContext_.logError @ core.js:20684
push../node_modules/@angular/core/fesm5/core.js.ErrorHandler.handleError @ core.js:12632
(anonymous) @ core.js:14878
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:388
push../node_modules/zone.js/dist/zone.js.Zone.run @ zone.js:138
push../node_modules/@angular/core/fesm5/core.js.NgZone.runOutsideAngular @ core.js:14102
push../node_modules/@angular/core/fesm5/core.js.ApplicationRef.tick @ core.js:14878
(anonymous) @ core.js:14762
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:388
onInvoke @ core.js:14143
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:387
push../node_modules/zone.js/dist/zone.js.Zone.run @ zone.js:138
push../node_modules/@angular/core/fesm5/core.js.NgZone.run @ core.js:14057
next @ core.js:14762
schedulerFn @ core.js:10238
push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.__tryOrUnsub @ Subscriber.js:196
push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.next @ Subscriber.js:134
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next @ Subscriber.js:77
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next @ Subscriber.js:54
push../node_modules/rxjs/_esm5/internal/Subject.js.Subject.next @ Subject.js:47
push../node_modules/@angular/core/fesm5/core.js.EventEmitter.emit @ core.js:10222
checkStable @ core.js:14112
onHasTask @ core.js:14156
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.hasTask @ zone.js:441
push../node_modules/zone.js/dist/zone.js.ZoneDelegate._updateTaskCount @ zone.js:461
push../node_modules/zone.js/dist/zone.js.Zone._updateTaskCount @ zone.js:285
push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:205
drainMicroTaskQueue @ zone.js:595
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:500
invokeTask @ zone.js:1540
globalZoneAwareCallback @ zone.js:1566
HomeComponent_Host.ngfactory.js? [sm]:1 ERROR CONTEXT DebugContext_ {view: {…}, nodeIndex: 0, nodeDef: {…}, elDef: {…}, elView: {…}}
Everton, I’m working through the tutorial and if I can help I will but right now I’m not ready. Keep trying!
I did not find it yet.
It worked!!
I can not figure out why, I installed and loaded a few times I used forums and nobody could get it all uninstalled again I downloaded the file and installed and started to work.
Nice work, thank you. 🙂
Please Could you show us how you soleve the issue, Im getiing the same error
I’m getting the same error.
I’m getting the same error.
hey plz tell me how you did solve this Error..
did anyone find a solution for this error i stil can’t resolve it i need help plz ,
i am getting this error on the front console
core.js:6014 ERROR SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse ()
at TokenStorageService.getAuthorities (token-storage.service.ts:48)
at SafeSubscriber._next (login.component.ts:48)
at SafeSubscriber.__tryOrUnsub (Subscriber.js:185)
at SafeSubscriber.next (Subscriber.js:124)
at Subscriber._next (Subscriber.js:72)
at Subscriber.next (Subscriber.js:49)
at MapSubscriber._next (map.js:35)
at MapSubscriber.next (Subscriber.js:49)
at FilterSubscriber._next (filter.js:33)
and this error on the backend
Expired JWT token -> Message: {}
io.jsonwebtoken.ExpiredJwtException: JWT expired at 2019-11-19T10:15:06Z. Current time: 2019-11-19T10:17:50Z, a difference of 164030 milliseconds. Allowed clock skew: 0 milliseconds.
at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:385) ~[jjwt-0.9.0.jar:0.9.0]
at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:481) ~[jjwt-0.9.0.jar:0.9.0]
at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:541) ~[jjwt-0.9.0.jar:0.9.0]
at com.looyas.demo.security.jwt.JwtProvider.validateJwtToken(JwtProvider.java:48) ~[classes/:na]
at com.looyas.demo.security.jwt.JwtAuthTokenFilter.doFilterInternal(JwtAuthTokenFilter.java:40) [classes/:na]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) [spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587) [tomcat-embed-core-9.0.24.jar:9.0.24]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.24.jar:9.0.24]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_181]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_181]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.24.jar:9.0.24]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_181]
2019-11-19 10:17:50.366 INFO 840 — [nio-8008-exec-1] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
Hi,
I don’t see the role filed in registration form ?! And when I tried to save a new user, it gaves me user role by default!! could u explain please? thanks
Hi kimo,
For Admin & PM role, you can register by sending HTTP POST request to the server.
Please view this video for more details:
https://www.youtube.com/watch?v=JPED8CG8G2w
Regards,
grokonez.
Hi Grokonez,
In backend everything is clear for me, but I have question about angular. What should I do to change role of registering user in form of registration. I dont want that user who is registating have default ‘user’. Can you explain, please, how I can send from angular to spring data of user with role that I can choose manualy, for example: “admin” and “user” and in database was saved user with choosen role. I have idea that I can write registration for all kind of users seperatly. It is a good idea, good practice? I dont think so. Can you help me with it?
Regards,
Oleksandr Turchanovskyi
Hi Oleksandr Turchanovskyi,
You can make a page that only Admin can access (e.g: Admin Board) to set authority (PM, User,… ) for other users 🙂
Regards,
grokonez.
Where are the css of all the component pages as per the ui look and feel shown in this blog as I am done with entire full stack as per this blog but page styles are very rough.
Hi rakesh,
You can find link to css (bootstrap) in
index.html
file.Regards,
grokonez.
hi, why in login form and register form use #username=”ngModel” not #username=”ngForm”. Because when that code in my IDE it can not find username.errors.required when use ngModel but when i change to ngForm it available. I use webstorm
Hello,
Thank you for your tutorial.
The only problem I have is that the JWT token does not expire. I am logged as long as I click ‘logout’. I think expiration is not working properly on t he frontend part. Or am I missing somethink?
Hi,
Thank you for the tutorial. It provided me a good intro in Angular and Token based authentication. Implementing your example exposed a security flow, I am trying to fix right now. TokenStorageService is using session storage to store the token. This is not a good practice since it leaves solution vulnerable to cross-site scripting (XSS) attacks. More info about the issue can be found here: vulnerable to cross-site scripting (XSS) attacks.
It would be great if you could propose a fix for this issue. Thank you for the great tutorial non the less.
Kind regards,
Bane
Hi Sir, I am facing problem in client side while Intercepting header request with Angular 7 code, when I am page loading then Authorization request header is not showing in network portion, please help
Hello,
Did you find any solution ?
I am facing the same problem. I am not sure that my AuthInterceptor is injected anywhere.
Thus, all my requests’ headers are empty.
If anyone has the solution, that would be awesome to share it with us.
Peace.
Okay sorry, I didn’t insert the httpInterceptorProviders in my app.module.ts file :
…
import { httpInterceptorProviders } from ‘…’;
…
providers: […, httpInterceptorProviders],
Hello,
I have the same error that Everton had;
In my session storage only token is defiend but username an authorities are not.
So, the getToken() method does not work !
Can I get some help please ?
what you need is, you have to include node module in your directory of project. Need to run? send me an email, I will send you the required file
rayhanshuvo.bd@gmail.com
I just have a doubt, after I authorize the user I want to take him to a feedback page I already have a feedback front-end and back-end but I don’t know how to let the user enter the feedback page after the authorization.
I hope you can help me or just show me some references
Hello sir,
I am facing this problem at client side when signin..what is the problem?
ERROR SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse at TokenStorageService.getAuthorities
can i get some help?
Me Too.
this tutorial is remarkable. congratulations!
Hello,
Thank you for this tutorial.
Can anyone help me ?
I’m having this problem ” GET http://localhost:8080/api/test/admin 401 ” when I try to access admin Board ,
even so I can access it with postman !
Same error for user board.
Thank you
Hello
Thank you for this tutorial,
I have a problem,
getToken() returns undefined
Can anyone help me ?
thank you
Hello
I change “accessToken” to “token” in class “JwtResponse”. After that everything was work correctly.
Regards
Aklikan
Are route guards not required for this application ?
Hi.
How can i after login show other data from database like email? If i go to home i see username, role and token.
Thanks.
Did any one resolve this problem i still can’t solve it i need help plz
ERROR SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse ()
at TokenStorageService.push../src/app/auth/token-storage.service.ts.TokenStorageService.getAuthorities (token-storage.service.ts:45)
at SafeSubscriber._next (login.component.ts:45)
Why i am getting this error..
Where are the css of all the component pages as per the ui look and feel shown in this blog as I am done with entire full stack as per this blog but page styles are very rough.
Push in the backend in AuthRestAPIs controller, in the section signing this code:
String jwt = jwtProvider.generateJwtToken(authentication);
UserPrinciple userPrinciple = (UserPrinciple) authentication.getPrincipal();
return ResponseEntity.ok(new JwtResponse(jwt, userPrinciple.getUsername(), authentication.getAuthorities()));
and Add to UserPrinciple
private String password;
private Collection authorities;
Got this error,
2020-08-29 12:33:06.630 ERROR 15112 — [nio-8090-exec-1] c.g.j.security.jwt.JwtAuthEntryPoint : Unauthorized error. Message – Full authentication is required to access this resource.
AuthenticationEntryPoint.commence() executed and throwing 401 error only when submitting form using angular.
Executed properly when checking same with postman.
Is there any reason ?
Nice and Clean Work Man. You save my project. Thanks a lot!
did you find any solution