added authentication

This commit is contained in:
Jakub Walkowiak 2020-12-20 18:55:45 +01:00
parent 9e2720ae88
commit 23d22b00e5
13 changed files with 149 additions and 28 deletions

View File

@ -1,9 +1,12 @@
import { AuthGuard } from './auth/auth.guard';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [
{ path: '', loadChildren: () => import('./subject/subject.module').then(m => m.SubjectModule) }
{ path: '', redirectTo: 'user', pathMatch: 'full' },
{ path: 'subject', loadChildren: () => import('./subject/subject.module').then(m => m.SubjectModule), canActivate: [AuthGuard] },
{ path: 'user', loadChildren: () => import('./user/user.module').then(m => m.UserModule) }
];
@NgModule({

View File

@ -1,10 +1,11 @@
import { AuthIntercpetor } from './auth/auth.interceptor';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientModule } from '@angular/common/http';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
@NgModule({
declarations: [
@ -16,7 +17,11 @@ import { HttpClientModule } from '@angular/common/http';
BrowserAnimationsModule,
HttpClientModule
],
providers: [],
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: AuthIntercpetor,
multi: true
}],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { AuthGuard } from './auth.guard';
describe('AuthGuard', () => {
let guard: AuthGuard;
beforeEach(() => {
TestBed.configureTestingModule({});
guard = TestBed.inject(AuthGuard);
});
it('should be created', () => {
expect(guard).toBeTruthy();
});
});

View File

@ -0,0 +1,21 @@
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private router: Router) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
if (localStorage.getItem('token') !== null) {
return true;
} else {
this.router.navigateByUrl('/user');
}
}
}

View File

@ -0,0 +1,32 @@
import { Router } from '@angular/router';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs";
import { tap } from "rxjs/operators";
@Injectable()
export class AuthIntercpetor implements HttpInterceptor {
constructor(private router: Router) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (localStorage.getItem('token') !== null) {
const request = req.clone({
headers: req.headers.set('Authorization', 'Bearer ' + localStorage.getItem('token'))
});
return next.handle(request).pipe(tap(
() => {},
err => {
localStorage.removeItem('token');
localStorage.removeItem('userId');
localStorage.removeItem('userName');
localStorage.removeItem('fullName');
this.router.navigateByUrl('/user');
}
));
} else {
return next.handle(req.clone());
}
}
}

View File

@ -1,6 +1,7 @@
<div class="login-form-container d-flex justify-content-center">
<div class="d-flex flex-column">
<form [formGroup]="loginForm" class="login-form d-flex flex-column mt-5">
<mat-form-field>
<mat-label>Username</mat-label>
<input matInput formControlName="userName" />
@ -8,11 +9,13 @@
<mat-form-field>
<mat-label>Password</mat-label>
<input matInput formControlName="password" />
<input matInput formControlName="password" type="password" />
</mat-form-field>
<div class="mt-4">
<button (click)="onLoginUser()" class="btn btn-primary">Save</button>
<button (click)="onLoginUser()" class="btn btn-primary">Sign in</button>
</div>
</form>
</div>
<a routerLink="/user/register">Registration</a>
</div>
</div>

View File

@ -30,9 +30,12 @@ export class LoginComponent implements OnInit {
});
}
onRegisterUser(): void {
onLoginUser(): void {
this.userSerice.login(this.loginForm.value).subscribe((auth: Auth) => {
localStorage.setItem('token', auth.token);
localStorage.setItem('userId', auth.user.id);
localStorage.setItem('userName', auth.user.userName);
localStorage.setItem('fullName', auth.user.fullName);
this.router.navigateByUrl('/subjects');
});
}

View File

@ -1,6 +1,7 @@
<div class="register-form-container d-flex justify-content-center">
<div class="d-flex flex-column">
<form [formGroup]="registerForm" class="register-form d-flex flex-column mt-5">
<mat-form-field>
<mat-label>Username</mat-label>
<input matInput formControlName="userName" />
@ -11,19 +12,31 @@
<input matInput formControlName="fullName" />
</mat-form-field>
<mat-form-field>
<mat-label>Password</mat-label>
<input matInput formControlName="password" />
</mat-form-field>
<div formGroupName="passwordForm" class="d-flex flex-column">
<mat-form-field>
<mat-label>Password</mat-label>
<input matInput formControlName="password" type="password" />
</mat-form-field>
<mat-form-field>
<mat-label>Repeated password</mat-label>
<input matInput formControlName="repeatedPassword" />
</mat-form-field>
<mat-form-field>
<mat-label>Repeated password</mat-label>
<input matInput formControlName="repeatedPassword" type="password" />
</mat-form-field>
<div style="color:#ff7355" *ngIf="registerForm.get(['passwordForm', 'password']).value != registerForm.get(['passwordForm', 'repeatedPassword']).value && registerForm.get(['passwordForm', 'repeatedPassword']).value != null">
Password does not match
</div>
</div>
<div class="mt-4">
<button (click)="onRegisterUser()" class="btn btn-primary">Save</button>
<button [disabled]="registerForm.invalid"
(click)="onRegisterUser()"
class="btn btn-primary">
Sign up
</button>
</div>
</form>
<a routerLink="/">Back to login page</a>
</div>
</div>

View File

@ -1,7 +1,8 @@
import { UserService } from './../../services/user.service';
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { FormGroup, FormControl, Validators, AbstractControl } from '@angular/forms';
import { Router } from '@angular/router';
import { User } from '../../interfaces/user.interface';
@Component({
selector: 'app-register',
@ -24,14 +25,27 @@ export class RegisterComponent implements OnInit {
return new FormGroup({
userName: new FormControl('', Validators.required),
fullName: new FormControl('', Validators.required),
password: new FormControl('', Validators.required),
repeatedPassword: new FormControl('', Validators.required)
passwordForm: new FormGroup({
password: new FormControl('', Validators.required),
repeatedPassword: new FormControl('', Validators.required)
}, this.passwordValidator)
});
}
private passwordValidator(form: AbstractControl): { invalid: boolean } {
if (form.get('password').value !== form.get('repeatedPassword').value) {
return {invalid: true};
}
}
onRegisterUser(): void {
this.userSerice.register(this.registerForm.value).subscribe(() => {
this.router.navigateByUrl('/subjects');
const user: User = {
userName: this.registerForm.get('userName').value,
fullName: this.registerForm.get('fullName').value,
password: this.registerForm.get(['passwordForm', 'password']).value
}
this.userSerice.register(user).subscribe(() => {
this.router.navigateByUrl('/user/login');
});
}

View File

@ -1,3 +1,5 @@
import { User } from './user.interface';
export interface Auth {
token: string;
user: User;
}

View File

@ -1,5 +1,5 @@
export interface User {
id?: number;
id?: string;
userName: string;
fullName: string;
password?: string;

View File

@ -5,7 +5,8 @@ import { RegisterComponent } from './components/register/register.component';
const routes: Routes = [
{ path: '', component: LoginComponent },
{ path: '', redirectTo: 'login', pathMatch: 'full'},
{ path: 'login', component: LoginComponent },
{ path: 'register', component: RegisterComponent }
];
@ -13,4 +14,4 @@ const routes: Routes = [
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class SubjectRoutingModule { }
export class UserRoutingModule { }

View File

@ -1,14 +1,22 @@
import { MatInputModule } from '@angular/material/input';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RegisterComponent } from './components/register/register.component';
import { LoginComponent } from './components/login/login.component';
import { ReactiveFormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { UserRoutingModule } from './user-routing.module';
@NgModule({
declarations: [RegisterComponent, LoginComponent],
imports: [
CommonModule
CommonModule,
ReactiveFormsModule,
MatFormFieldModule,
MatInputModule,
UserRoutingModule
]
})
export class UserModule { }