Skip to content

Commit 1ac0f4e

Browse files
committed
first commit
1 parent f63aa98 commit 1ac0f4e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1143
-501
lines changed

README.md

+78-14
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,91 @@
1-
# Angular16JwtAuth
1+
# Angular 16 JWT Authentication & Authorization example with Rest API
22

3-
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 16.0.2.
3+
Build Angular 16 JWT Authentication & Authorization example with Rest Api, HttpOnly Cookie and JWT (including HttpInterceptor, Router & Form Validation).
4+
- JWT Authentication Flow for User Registration (Signup) & User Login
5+
- Project Structure with HttpInterceptor, Router
6+
- Way to implement HttpInterceptor
7+
- How to store JWT token in HttpOnly Cookie
8+
- Creating Login, Signup Components with Form Validation
9+
- Angular Components for accessing protected Resources
10+
- How to add a dynamic Navigation Bar to Angular App
11+
- Working with Browser Session Storage
412

5-
## Development server
13+
## Flow for User Registration and User Login
14+
For JWT – Token based Authentication with Rest API, we’re gonna call 2 endpoints:
15+
- POST `api/auth/signup` for User Registration
16+
- POST `api/auth/signin` for User Login
17+
- POST `api/auth/signout` for User Logout
618

7-
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
19+
You can take a look at following flow to have an overview of Requests and Responses that Angular 16 JWT Authentication & Authorization Client will make or receive.
820

9-
## Code scaffolding
21+
![angular-16-jwt-authentication-authorization-flow](angular-16-jwt-authentication-authorization-flow.png)
1022

11-
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
23+
## Angular JWT App Diagram with Router and HttpInterceptor
24+
![angular-16-jwt-authentication](angular-16-jwt-authentication.png)
1225

13-
## Build
26+
For more detail, please visit the tutorial:
27+
> [Angular 16 JWT Authentication & Authorization with Web API example](https://www.bezkoder.com/angular-16-jwt-auth/)
1428
15-
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
29+
> [Angular 16 Logout when Token is expired](https://www.bezkoder.com/logout-when-token-expired-angular-16/)
1630
17-
## Running unit tests
31+
> [Angular 16 Refresh Token with Interceptor & JWT example](https://www.bezkoder.com/angular-16-refresh-token/)
1832
19-
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
33+
## With Spring Boot back-end
2034

21-
## Running end-to-end tests
35+
> [Angular 16 + Spring Boot: JWT Authentication and Authorization example](https://www.bezkoder.com/angular-16-spring-boot-jwt-auth/)
2236
23-
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
37+
## With Node.js Express back-end
2438

25-
## Further help
39+
> [Angular 16 + Node.js Express: JWT Authentication and Authorization example](https://www.bezkoder.com/node-js-angular-16-jwt-auth/)
2640
27-
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
41+
Run `ng serve --port 8081` for a dev server. Navigate to `http://localhost:8081/`.
42+
43+
## More practice
44+
> [Angular 16 CRUD example with Rest API](https://www.bezkoder.com/angular-16-crud-example/)
45+
46+
> [Angular 16 Pagination example](https://www.bezkoder.com/angular-16-pagination-ngx/)
47+
48+
> [Angular 16 File upload example with Progress bar](https://www.bezkoder.com/angular-16-file-upload/)
49+
50+
> [Angular 16 Form Validation example](https://www.bezkoder.com/angular-16-form-validation/)
51+
52+
Fullstack with Node:
53+
> [Angular 16 + Node Express + MySQL example](https://www.bezkoder.com/angular-16-node-js-express-mysql/)
54+
55+
> [Angular 16 + Node Express + PostgreSQL example](https://www.bezkoder.com/angular-16-node-js-express-postgresql/)
56+
57+
> [Angular 16 + Node Express + MongoDB example](https://www.bezkoder.com/angular-16-node-js-express-mongodb/)
58+
59+
> [Angular 16 + Node Express: File upload example](https://www.bezkoder.com/angular-16-node-express-file-upload/)
60+
61+
Fullstack with Spring Boot:
62+
> [Angular 16 + Spring Boot example](https://www.bezkoder.com/spring-boot-angular-16-crud/)
63+
64+
> [Angular 16 + Spring Boot + MySQL example](https://www.bezkoder.com/spring-boot-angular-16-mysql/)
65+
66+
> [Angular 16 + Spring Boot + PostgreSQL example](https://www.bezkoder.com/spring-boot-angular-16-postgresql/)
67+
68+
> [Angular 16 + Spring Boot + MongoDB example](https://www.bezkoder.com/spring-boot-angular-16-mongodb/)
69+
70+
> [Angular 16 + Spring Boot: File upload example](https://www.bezkoder.com/angular-16-spring-boot-file-upload/)
71+
72+
Fullstack with Django:
73+
> [Angular + Django example](https://www.bezkoder.com/django-angular-13-crud-rest-framework/)
74+
75+
> [Angular + Django + MySQL](https://www.bezkoder.com/django-angular-mysql/)
76+
77+
> [Angular + Django + PostgreSQL](https://www.bezkoder.com/django-angular-postgresql/)
78+
79+
> [Angular + Django + MongoDB](https://www.bezkoder.com/django-angular-mongodb/)
80+
81+
Serverless with Firebase:
82+
> [Angular 16 Firebase CRUD with Realtime DataBase](https://www.bezkoder.com/angular-16-firebase-crud/)
83+
84+
> [Angular 16 Firestore CRUD example](https://www.bezkoder.com/angular-16-firestore-crud/)
85+
86+
> [Angular 16 Firebase Storage: File Upload/Display/Delete example](https://www.bezkoder.com/angular-16-firebase-storage/)
87+
88+
Integration (run back-end & front-end on same server/port)
89+
> [How to integrate Angular with Node Restful Services](https://www.bezkoder.com/integrate-angular-12-node-js/)
90+
91+
> [How to Integrate Angular with Spring Boot Rest API](https://www.bezkoder.com/integrate-angular-12-spring-boot/)
Loading

angular-16-jwt-authentication.png

22.6 KB
Loading

package-lock.json

+37
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@angular/platform-browser": "^16.0.0",
1919
"@angular/platform-browser-dynamic": "^16.0.0",
2020
"@angular/router": "^16.0.0",
21+
"bootstrap": "^4.6.2",
2122
"rxjs": "~7.8.0",
2223
"tslib": "^2.3.0",
2324
"zone.js": "~0.13.0"

src/app/_helpers/http.interceptor.ts

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { Injectable } from '@angular/core';
2+
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HTTP_INTERCEPTORS, HttpErrorResponse } from '@angular/common/http';
3+
import { Observable, throwError } from 'rxjs';
4+
import { catchError } from 'rxjs/operators';
5+
6+
import { StorageService } from '../_services/storage.service';
7+
import { EventBusService } from '../_shared/event-bus.service';
8+
import { EventData } from '../_shared/event.class';
9+
10+
@Injectable()
11+
export class HttpRequestInterceptor implements HttpInterceptor {
12+
private isRefreshing = false;
13+
14+
constructor(private storageService: StorageService, private eventBusService: EventBusService) { }
15+
16+
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
17+
req = req.clone({
18+
withCredentials: true,
19+
});
20+
21+
return next.handle(req).pipe(
22+
catchError((error) => {
23+
// logout when token is expired
24+
/*
25+
if (
26+
error instanceof HttpErrorResponse &&
27+
!req.url.includes('auth/signin') &&
28+
error.status === 401
29+
) {
30+
return this.handle401Error(req, next);
31+
}
32+
*/
33+
return throwError(() => error);
34+
})
35+
);
36+
}
37+
38+
private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
39+
if (!this.isRefreshing) {
40+
this.isRefreshing = true;
41+
42+
if (this.storageService.isLoggedIn()) {
43+
this.eventBusService.emit(new EventData('logout', null));
44+
}
45+
}
46+
47+
return next.handle(request);
48+
}
49+
}
50+
51+
export const httpInterceptorProviders = [
52+
{ provide: HTTP_INTERCEPTORS, useClass: HttpRequestInterceptor, multi: true },
53+
];
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { TestBed } from '@angular/core/testing';
2+
3+
import { AuthService } from './auth.service';
4+
5+
describe('AuthService', () => {
6+
let service: AuthService;
7+
8+
beforeEach(() => {
9+
TestBed.configureTestingModule({});
10+
service = TestBed.inject(AuthService);
11+
});
12+
13+
it('should be created', () => {
14+
expect(service).toBeTruthy();
15+
});
16+
});

src/app/_services/auth.service.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { Injectable } from '@angular/core';
2+
import { HttpClient, HttpHeaders } from '@angular/common/http';
3+
import { Observable } from 'rxjs';
4+
5+
const AUTH_API = 'http://localhost:8080/api/auth/';
6+
7+
const httpOptions = {
8+
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
9+
};
10+
11+
@Injectable({
12+
providedIn: 'root',
13+
})
14+
export class AuthService {
15+
constructor(private http: HttpClient) {}
16+
17+
login(username: string, password: string): Observable<any> {
18+
return this.http.post(
19+
AUTH_API + 'signin',
20+
{
21+
username,
22+
password,
23+
},
24+
httpOptions
25+
);
26+
}
27+
28+
register(username: string, email: string, password: string): Observable<any> {
29+
return this.http.post(
30+
AUTH_API + 'signup',
31+
{
32+
username,
33+
email,
34+
password,
35+
},
36+
httpOptions
37+
);
38+
}
39+
40+
logout(): Observable<any> {
41+
return this.http.post(AUTH_API + 'signout', { }, httpOptions);
42+
}
43+
}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { TestBed } from '@angular/core/testing';
2+
3+
import { StorageService } from './storage.service';
4+
5+
describe('StorageService', () => {
6+
let service: StorageService;
7+
8+
beforeEach(() => {
9+
TestBed.configureTestingModule({});
10+
service = TestBed.inject(StorageService);
11+
});
12+
13+
it('should be created', () => {
14+
expect(service).toBeTruthy();
15+
});
16+
});

src/app/_services/storage.service.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { Injectable } from '@angular/core';
2+
3+
const USER_KEY = 'auth-user';
4+
5+
@Injectable({
6+
providedIn: 'root'
7+
})
8+
export class StorageService {
9+
constructor() {}
10+
11+
clean(): void {
12+
window.sessionStorage.clear();
13+
}
14+
15+
public saveUser(user: any): void {
16+
window.sessionStorage.removeItem(USER_KEY);
17+
window.sessionStorage.setItem(USER_KEY, JSON.stringify(user));
18+
}
19+
20+
public getUser(): any {
21+
const user = window.sessionStorage.getItem(USER_KEY);
22+
if (user) {
23+
return JSON.parse(user);
24+
}
25+
26+
return null;
27+
}
28+
29+
public isLoggedIn(): boolean {
30+
const user = window.sessionStorage.getItem(USER_KEY);
31+
if (user) {
32+
return true;
33+
}
34+
35+
return false;
36+
}
37+
}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { TestBed } from '@angular/core/testing';
2+
3+
import { UserService } from './user.service';
4+
5+
describe('UserService', () => {
6+
let service: UserService;
7+
8+
beforeEach(() => {
9+
TestBed.configureTestingModule({});
10+
service = TestBed.inject(UserService);
11+
});
12+
13+
it('should be created', () => {
14+
expect(service).toBeTruthy();
15+
});
16+
});

src/app/_services/user.service.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Injectable } from '@angular/core';
2+
import { HttpClient } from '@angular/common/http';
3+
import { Observable } from 'rxjs';
4+
5+
const API_URL = 'http://localhost:8080/api/test/';
6+
7+
@Injectable({
8+
providedIn: 'root',
9+
})
10+
export class UserService {
11+
constructor(private http: HttpClient) {}
12+
13+
getPublicContent(): Observable<any> {
14+
return this.http.get(API_URL + 'all', { responseType: 'text' });
15+
}
16+
17+
getUserBoard(): Observable<any> {
18+
return this.http.get(API_URL + 'user', { responseType: 'text' });
19+
}
20+
21+
getModeratorBoard(): Observable<any> {
22+
return this.http.get(API_URL + 'mod', { responseType: 'text' });
23+
}
24+
25+
getAdminBoard(): Observable<any> {
26+
return this.http.get(API_URL + 'admin', { responseType: 'text' });
27+
}
28+
}

0 commit comments

Comments
 (0)