From 6103ed079886c416d3b2321b5018bcf053dc823a Mon Sep 17 00:00:00 2001 From: rawan osama Date: Thu, 19 Oct 2023 12:30:20 +0300 Subject: [PATCH 1/2] login form with auth guard --- product-task/db.json | 27 +++++ product-task/src/app/app-routing.module.ts | 5 +- product-task/src/app/app.module.ts | 4 +- .../app/components/guard/auth-class.guard.ts | 25 +++++ .../app/components/login/login.component.html | 39 +++++++ .../app/components/login/login.component.scss | 8 ++ .../app/components/login/login.component.ts | 100 ++++++++++++++++++ .../app/layout/navbar/navbar.component.html | 4 +- .../src/app/layout/navbar/navbar.component.ts | 5 + .../app/product/services/products.service.ts | 6 ++ product-task/src/app/user/model/iuser.ts | 7 ++ .../src/app/user/services/user.service.ts | 37 +++++++ 12 files changed, 264 insertions(+), 3 deletions(-) create mode 100644 product-task/src/app/components/guard/auth-class.guard.ts create mode 100644 product-task/src/app/components/login/login.component.html create mode 100644 product-task/src/app/components/login/login.component.scss create mode 100644 product-task/src/app/components/login/login.component.ts create mode 100644 product-task/src/app/user/model/iuser.ts create mode 100644 product-task/src/app/user/services/user.service.ts diff --git a/product-task/db.json b/product-task/db.json index 77296c1..d8e1541 100644 --- a/product-task/db.json +++ b/product-task/db.json @@ -27,5 +27,32 @@ "type": "laptop", "id": 6 } + ], + "users": [ + { + "id": 1, + "email": "rawan", + "password": "rawan1234" + }, + { + "id": 2, + "email": "ahmed", + "password": "ahmed" + }, + { + "id": 3, + "email": "mohamed", + "password": "mohamed" + }, + { + "id": 5, + "email": "yousef", + "password": "yousef" + }, + { + "id": 37, + "email": "osama", + "password": "osama" + } ] } \ No newline at end of file diff --git a/product-task/src/app/app-routing.module.ts b/product-task/src/app/app-routing.module.ts index f38ccaf..7b12fb0 100644 --- a/product-task/src/app/app-routing.module.ts +++ b/product-task/src/app/app-routing.module.ts @@ -1,12 +1,15 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; +import { AuthClassGuard } from './components/guard/auth-class.guard'; +import { LoginComponent } from './components/login/login.component'; import { ProductAngularMaterialComponent } from './components/product-angular-material/product-angular-material.component'; import { ProductComponent } from './components/product/product.component'; import { TextComponent } from './components/product/text/text.component'; const routes: Routes = [ {path:'product',component:ProductComponent}, - {path:'productAngular',component:ProductAngularMaterialComponent}, + {path:'productAngular',component:ProductAngularMaterialComponent,canActivate:[AuthClassGuard]}, + {path:'login',component:LoginComponent} ]; diff --git a/product-task/src/app/app.module.ts b/product-task/src/app/app.module.ts index 3ec5009..30f1b63 100644 --- a/product-task/src/app/app.module.ts +++ b/product-task/src/app/app.module.ts @@ -23,6 +23,7 @@ import { DialogComponent } from './components/dialog/dialog.component'; import {MatSnackBar, MatSnackBarModule} from '@angular/material/snack-bar'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateHttpLoader } from '@ngx-translate/http-loader'; +import { LoginComponent } from './components/login/login.component'; export function createTranslateLoader(http:HttpClient){ @@ -36,7 +37,8 @@ export function createTranslateLoader(http:HttpClient){ ProductComponent, TextComponent, ProductAngularMaterialComponent, - DialogComponent + DialogComponent, + LoginComponent ], imports: [ diff --git a/product-task/src/app/components/guard/auth-class.guard.ts b/product-task/src/app/components/guard/auth-class.guard.ts new file mode 100644 index 0000000..72d2842 --- /dev/null +++ b/product-task/src/app/components/guard/auth-class.guard.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router'; +import { Observable } from 'rxjs'; +import { UserService } from 'src/app/user/services/user.service'; + +@Injectable({ + providedIn: 'root' +}) +export class AuthClassGuard implements CanActivate { + constructor(private authUser:UserService){ + + } + canActivate( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree + {if (this.authUser.isLogged()) { + return true; + } + else{ + return false + } + + } + +} diff --git a/product-task/src/app/components/login/login.component.html b/product-task/src/app/components/login/login.component.html new file mode 100644 index 0000000..ce3ad72 --- /dev/null +++ b/product-task/src/app/components/login/login.component.html @@ -0,0 +1,39 @@ +
+ + + ID + + + + Email + + + + Password + + + +
+ + +
+ +
+ + + +
+ + Email + + + + Password + + +
+ + +
+ +
diff --git a/product-task/src/app/components/login/login.component.scss b/product-task/src/app/components/login/login.component.scss new file mode 100644 index 0000000..a86506c --- /dev/null +++ b/product-task/src/app/components/login/login.component.scss @@ -0,0 +1,8 @@ +.form{ + margin-top: 40px; + padding: 20px; + display: flex; + flex-direction: column; + align-items: flex-center; + background-color: beige; +} diff --git a/product-task/src/app/components/login/login.component.ts b/product-task/src/app/components/login/login.component.ts new file mode 100644 index 0000000..637903d --- /dev/null +++ b/product-task/src/app/components/login/login.component.ts @@ -0,0 +1,100 @@ +import { Component } from '@angular/core'; +import { FormControl, FormGroup } from '@angular/forms'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Iuser } from 'src/app/user/model/iuser'; +import { UserService } from 'src/app/user/services/user.service'; + + +@Component({ + selector: 'app-login', + templateUrl: './login.component.html', + styleUrls: ['./login.component.scss'] +}) +export class LoginComponent { + RegisterForm!: FormGroup ; + LoginForm!:FormGroup; + userList:Iuser[] =[]; + user:Iuser[] =[];; + showRegisterForm:boolean=true; + showLoginForm:boolean=false; + + + +constructor(private route:ActivatedRoute,private router:Router,private userService:UserService,private _snackBar: MatSnackBar){ + +} + + createRegisterForm(){ + this.RegisterForm = new FormGroup({ + id:new FormControl(''), + email: new FormControl(''), + password:new FormControl('') + }); + } + showLogin(){ + this.showRegisterForm=false; + this.showLoginForm=true; + } + showRegister(){ + this.showRegisterForm=true; + this.showLoginForm=false; + } + createLoginForm(){ + this.LoginForm = new FormGroup({ + email: new FormControl(''), + password:new FormControl('') + }); + } + + ngOnInit(){ + this.createRegisterForm(); + this.createLoginForm(); + this.getAllUsers(); + + } + openSnackBar(message: string, action: string) { + this._snackBar.open(message, action); + } + addUser(){ + this.userService.postUsers(this.RegisterForm.value) + .subscribe(_=>{ + this.RegisterForm.reset(); + this.showLogin(); + this.openSnackBar('User Registered Successfully', 'OK'); + }) + } + logoutUser(){ + localStorage.removeItem('token'); + + } + getAllUsers(){ + + this.userService.getUsers().subscribe(data=>{ + this.user= data; + }) + + } + + checkRegisteredUser(email:any){ + console.log(email); + for (let i = 0; i < this.user.length; i++) { + if (email==this.user[i].email) { + localStorage.setItem('token','1234'); + this.router.navigate(['productAngular']); + this.openSnackBar('User Login Successfully', 'OK'); + } + else { + this.showRegister(); + this.openSnackBar('Must Register First', 'OK'); + + } + + } + + } + + } + + + diff --git a/product-task/src/app/layout/navbar/navbar.component.html b/product-task/src/app/layout/navbar/navbar.component.html index 382d5e3..9d282db 100644 --- a/product-task/src/app/layout/navbar/navbar.component.html +++ b/product-task/src/app/layout/navbar/navbar.component.html @@ -8,7 +8,9 @@ - + diff --git a/product-task/src/app/layout/navbar/navbar.component.ts b/product-task/src/app/layout/navbar/navbar.component.ts index 1161628..3559bab 100644 --- a/product-task/src/app/layout/navbar/navbar.component.ts +++ b/product-task/src/app/layout/navbar/navbar.component.ts @@ -1,9 +1,14 @@ import { Component } from '@angular/core'; +import { UserService } from 'src/app/user/services/user.service'; @Component({ selector: 'app-navbar', templateUrl: './navbar.component.html' }) export class NavbarComponent { + constructor(){ + + } + } diff --git a/product-task/src/app/product/services/products.service.ts b/product-task/src/app/product/services/products.service.ts index 11e3a2c..a7638e4 100644 --- a/product-task/src/app/product/services/products.service.ts +++ b/product-task/src/app/product/services/products.service.ts @@ -8,8 +8,10 @@ import { IProduct } from '../models/iproduct'; }) export class ProductsService { product:IProduct[]; + constructor(private http : HttpClient) { this.product=[] + } postProducts(data : any){ return this.http.post("http://localhost:3000/products",data) @@ -47,4 +49,8 @@ product:IProduct[]; map((response:[]) => response.map(item => item ['brand'])) ) } + + + + } diff --git a/product-task/src/app/user/model/iuser.ts b/product-task/src/app/user/model/iuser.ts new file mode 100644 index 0000000..b95f8ae --- /dev/null +++ b/product-task/src/app/user/model/iuser.ts @@ -0,0 +1,7 @@ +export interface Iuser { + id:number, + email:string, + password:string + } + + diff --git a/product-task/src/app/user/services/user.service.ts b/product-task/src/app/user/services/user.service.ts new file mode 100644 index 0000000..f308a78 --- /dev/null +++ b/product-task/src/app/user/services/user.service.ts @@ -0,0 +1,37 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { map } from 'rxjs'; +import { Iuser } from '../model/iuser'; + + +@Injectable({ + providedIn: 'root' +}) +export class UserService { + user:Iuser[]; + constructor(public http : HttpClient) { + this.user=[]; + } + + + postUsers(data : any){ + return this.http.post("http://localhost:3000/users",data) + .pipe(map((res:any)=>{ + return res; + })) + } + + getUsers(){ + return this.http.get("http://localhost:3000/users") + .pipe(map((res:any)=>{ + return res; + })) + } + + + + isLogged(){ + return (localStorage.getItem('token'))? true:false; + } + +} From 32453631452d28947084209eb5bcd423c37e099b Mon Sep 17 00:00:00 2001 From: rawan osama Date: Thu, 19 Oct 2023 16:21:13 +0300 Subject: [PATCH 2/2] token interceptor --- product-task/src/app/app.module.ts | 12 +++++++--- .../app/components/login/login.component.ts | 10 ++++---- .../services/token-interceptor.service.ts | 23 +++++++++++++++++++ .../src/app/user/services/user.service.ts | 7 +++++- 4 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 product-task/src/app/user/services/token-interceptor.service.ts diff --git a/product-task/src/app/app.module.ts b/product-task/src/app/app.module.ts index 30f1b63..b986e54 100644 --- a/product-task/src/app/app.module.ts +++ b/product-task/src/app/app.module.ts @@ -3,7 +3,7 @@ import { BrowserModule } from '@angular/platform-browser'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { NavbarComponent } from './layout/navbar/navbar.component'; -import {HttpClient, HttpClientModule} from '@angular/common/http' +import {HttpClient, HttpClientModule,HTTP_INTERCEPTORS} from '@angular/common/http' import { FormsModule, ReactiveFormsModule,FormControl } from '@angular/forms'; import { ProductComponent } from './components/product/product.component'; import { TextComponent } from './components/product/text/text.component'; @@ -24,7 +24,7 @@ import {MatSnackBar, MatSnackBarModule} from '@angular/material/snack-bar'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { LoginComponent } from './components/login/login.component'; - +import { TokenInterceptorService } from './user/services/token-interceptor.service'; export function createTranslateLoader(http:HttpClient){ return new TranslateHttpLoader(http,'../assets/i18n/','.json'); @@ -70,7 +70,13 @@ export function createTranslateLoader(http:HttpClient){ ], - providers: [], + providers: [{ + provide:HTTP_INTERCEPTORS, + useClass:TokenInterceptorService, + multi:true + } + +], bootstrap: [AppComponent] }) export class AppModule { } diff --git a/product-task/src/app/components/login/login.component.ts b/product-task/src/app/components/login/login.component.ts index 637903d..e4a90c4 100644 --- a/product-task/src/app/components/login/login.component.ts +++ b/product-task/src/app/components/login/login.component.ts @@ -66,6 +66,9 @@ constructor(private route:ActivatedRoute,private router:Router,private userServi } logoutUser(){ localStorage.removeItem('token'); + this.openSnackBar('Logout Successfully', 'OK'); + + } getAllUsers(){ @@ -77,17 +80,14 @@ constructor(private route:ActivatedRoute,private router:Router,private userServi } checkRegisteredUser(email:any){ - console.log(email); for (let i = 0; i < this.user.length; i++) { if (email==this.user[i].email) { + this.openSnackBar('User Login Successfully', 'OK'); localStorage.setItem('token','1234'); this.router.navigate(['productAngular']); - this.openSnackBar('User Login Successfully', 'OK'); } - else { + else{ this.showRegister(); - this.openSnackBar('Must Register First', 'OK'); - } } diff --git a/product-task/src/app/user/services/token-interceptor.service.ts b/product-task/src/app/user/services/token-interceptor.service.ts new file mode 100644 index 0000000..2a87602 --- /dev/null +++ b/product-task/src/app/user/services/token-interceptor.service.ts @@ -0,0 +1,23 @@ +import { Injectable,Injector } from '@angular/core'; +import{HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http' +import { Observable } from 'rxjs'; +import { UserService } from './user.service'; + +@Injectable({ + providedIn: 'root' +}) +export class TokenInterceptorService implements HttpInterceptor{ + + constructor(private injector : Injector) { } + + intercept(req:any, next:any){ + let userService = this.injector.get(UserService); + let tokenizedReq = req.clone({ + setHeaders:{ + Authorization:`${userService.getToken()}` + } + }) + return next.handle(tokenizedReq); + + } +} diff --git a/product-task/src/app/user/services/user.service.ts b/product-task/src/app/user/services/user.service.ts index f308a78..81a21d4 100644 --- a/product-task/src/app/user/services/user.service.ts +++ b/product-task/src/app/user/services/user.service.ts @@ -1,4 +1,4 @@ -import { HttpClient } from '@angular/common/http'; +import { HttpClient , HttpHeaders, HttpInterceptor, withInterceptors} from '@angular/common/http'; import { Injectable } from '@angular/core'; import { map } from 'rxjs'; import { Iuser } from '../model/iuser'; @@ -22,6 +22,7 @@ export class UserService { } getUsers(){ + return this.http.get("http://localhost:3000/users") .pipe(map((res:any)=>{ return res; @@ -34,4 +35,8 @@ export class UserService { return (localStorage.getItem('token'))? true:false; } + getToken(){ + return localStorage.getItem('token'); + } + }