Adding loging logout logic
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
<div class="container-fluid">
|
||||
<div class="row flex-nowrap">
|
||||
<div class="col-auto col-md-3 col-xl-2 px-sm-2 px-0 bg-dark" style="max-width: 200px;">
|
||||
<login></login>
|
||||
<logout></logout>
|
||||
<sidenav class="sticky-top"></sidenav>
|
||||
</div>
|
||||
<div class="col py-3">
|
||||
@@ -13,3 +15,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons';
|
||||
import { ReactiveFormsModule } from "@angular/forms";
|
||||
import { HttpClientModule, HTTP_INTERCEPTORS } from "@angular/common/http";
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
@@ -9,20 +11,31 @@ import { AppComponent } from './app.component';
|
||||
import { SidenavComponent } from "./layout/sidenav/sidenav.component";
|
||||
import { FlashmessagesComponent } from "./layout/flashmessages/flashmessages.component";
|
||||
import { FlashmessagesService } from "./layout/flashmessages/flashmessages.service";
|
||||
import { LoginComponent, LogoutComponent } from "./layout/auth/auth.component";
|
||||
import { AuthService } from "./layout/auth/auth.service";
|
||||
import { AuthInterceptor } from "./layout/auth/auth.interceptor"
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
SidenavComponent,
|
||||
FlashmessagesComponent
|
||||
FlashmessagesComponent,
|
||||
LoginComponent,
|
||||
LogoutComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
AppRoutingModule,
|
||||
NgbModule,
|
||||
NgxBootstrapIconsModule.pick(allIcons),
|
||||
ReactiveFormsModule,
|
||||
HttpClientModule,
|
||||
],
|
||||
providers: [
|
||||
FlashmessagesService,
|
||||
AuthService,
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
|
||||
],
|
||||
providers: [FlashmessagesService],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
||||
103
front/app/src/app/layout/auth/auth.component.ts
Normal file
103
front/app/src/app/layout/auth/auth.component.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import {Component, ElementRef, EventEmitter, Output, ViewChild} from "@angular/core";
|
||||
import {FormBuilder, FormGroup, Validators} from "@angular/forms";
|
||||
import {Router} from "@angular/router";
|
||||
import {AuthService} from "./auth.service";
|
||||
import {NgbModal} from "@ng-bootstrap/ng-bootstrap";
|
||||
|
||||
@Component({
|
||||
selector: 'login',
|
||||
template: `
|
||||
<button class="btn btn-lg btn-outline-primary" (click)="openLoginModal()">Login</button>
|
||||
<ng-template #loginModal let-modal>
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="modal-basic-title">Login</h4>
|
||||
<button type="button" class="btn-close" aria-label="Close"
|
||||
(click)="modal.dismiss('Cross click')"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form [formGroup]="form">
|
||||
<fieldset>
|
||||
<legend>Login</legend>
|
||||
<div class="form-field">
|
||||
<label>Username:</label>
|
||||
<input name="username" formControlName="username">
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label>Password:</label>
|
||||
<input name="password" formControlName="password"
|
||||
type="password">
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="form-buttons">
|
||||
<button class="button button-primary"
|
||||
(click)="this.login()">Login</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</ng-template>
|
||||
`
|
||||
})
|
||||
export class LoginComponent {
|
||||
@Output() loginSuccess = new EventEmitter<string>()
|
||||
|
||||
@ViewChild('loginModal')
|
||||
loginModal!: ElementRef;
|
||||
|
||||
form: FormGroup;
|
||||
|
||||
constructor(private fb:FormBuilder,
|
||||
private authService: AuthService,
|
||||
private modalService: NgbModal
|
||||
|
||||
) {
|
||||
this.form = this.fb.group({
|
||||
username: ['',Validators.required],
|
||||
password: ['',Validators.required]
|
||||
});
|
||||
|
||||
this.authService.onAuthenticationRequired$.subscribe((required: boolean) => {
|
||||
if (required) {
|
||||
this.openLoginModal()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
openLoginModal() {
|
||||
this.modalService.open(this.loginModal, { ariaLabelledBy: 'modal-basic-title' }).result.then(
|
||||
);
|
||||
}
|
||||
|
||||
login() {
|
||||
const val = this.form.value;
|
||||
|
||||
if (val.username && val.password) {
|
||||
this.authService.login(val.username, val.password)
|
||||
.subscribe((answer: string) => {
|
||||
this.modalService.dismissAll();
|
||||
this.loginSuccess.emit(answer)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'logout',
|
||||
template: `
|
||||
<button class="btn btn-lg btn-outline-primary" (click)="logout()">Logout</button>
|
||||
`
|
||||
})
|
||||
export class LogoutComponent {
|
||||
@Output() logoutSuccess = new EventEmitter()
|
||||
|
||||
constructor(private authService: AuthService) {
|
||||
}
|
||||
|
||||
logout() {
|
||||
this.authService.logout()
|
||||
.subscribe(() => {
|
||||
this.logoutSuccess.emit()
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
34
front/app/src/app/layout/auth/auth.interceptor.ts
Normal file
34
front/app/src/app/layout/auth/auth.interceptor.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { HttpErrorResponse, HttpHandler, HttpInterceptor, HttpRequest } from "@angular/common/http";
|
||||
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { catchError } from "rxjs/operators";
|
||||
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
@Injectable()
|
||||
export class AuthInterceptor implements HttpInterceptor {
|
||||
|
||||
constructor(private auth: AuthService) {}
|
||||
|
||||
intercept(req: HttpRequest<any>, next: HttpHandler) {
|
||||
const authToken = this.auth.getAuthorizationToken();
|
||||
let authReq: HttpRequest<any>;
|
||||
if (authToken) {
|
||||
authReq = req.clone({
|
||||
headers: req.headers.set('Authorization', authToken)
|
||||
});
|
||||
} else {
|
||||
authReq = req;
|
||||
}
|
||||
|
||||
return next.handle(authReq).pipe(
|
||||
catchError((error: HttpErrorResponse) => {
|
||||
if (error.status && error.status == 401) {
|
||||
this.auth.requestAuth();
|
||||
}
|
||||
return throwError(() => error);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
63
front/app/src/app/layout/auth/auth.service.ts
Normal file
63
front/app/src/app/layout/auth/auth.service.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { HttpClient, HttpHeaders, HttpParams } from "@angular/common/http";
|
||||
|
||||
import { map } from "rxjs/operators";
|
||||
import { Subject } from "rxjs";
|
||||
|
||||
import { FlashmessagesService } from "../flashmessages/flashmessages.service";
|
||||
|
||||
export interface token_answer {
|
||||
access_token: string,
|
||||
token_type: string
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
private access_token: string | null;
|
||||
|
||||
private authenticationRequired = new Subject<boolean>();
|
||||
onAuthenticationRequired$ = this.authenticationRequired.asObservable();
|
||||
|
||||
constructor(private http: HttpClient,
|
||||
private flashMessage: FlashmessagesService) {
|
||||
this.access_token = localStorage.getItem('authtoken')
|
||||
}
|
||||
|
||||
login(username:string, password:string ) {
|
||||
const body = new HttpParams()
|
||||
.set('username', username)
|
||||
.set('password', password);
|
||||
|
||||
return this.http.post<token_answer>('/api/v1/auth/login', body.toString(),
|
||||
{
|
||||
headers: new HttpHeaders()
|
||||
.set('Content-Type', 'application/x-www-form-urlencoded')
|
||||
}).pipe(map( v => {
|
||||
localStorage.setItem('authtoken', v.access_token);
|
||||
this.access_token = v.access_token
|
||||
this.flashMessage.success('Login successful. Welcome ' + username);
|
||||
return username
|
||||
} ));
|
||||
}
|
||||
|
||||
logout() {
|
||||
return this.http.post<token_answer>('/api/v1/auth/logout', '',
|
||||
{
|
||||
headers: new HttpHeaders()
|
||||
}).pipe(map( v => {
|
||||
localStorage.removeItem('authtoken');
|
||||
this.access_token = null;
|
||||
this.flashMessage.success('Logout successful. Goodbye');
|
||||
} ));
|
||||
}
|
||||
|
||||
getAuthorizationToken() {
|
||||
return `Bearer ${this.access_token}`;
|
||||
}
|
||||
|
||||
requestAuth() {
|
||||
localStorage.removeItem('authtoken');
|
||||
this.access_token = null;
|
||||
this.authenticationRequired.next(true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user