mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2024-12-20 21:43:06 +00:00
Merge pull request #1318 from GNS3/enhancement-JWT/1228
I have modified the JWT Interceptor and added refresh token functiona…
This commit is contained in:
commit
b430ab9a1c
@ -1,35 +1,42 @@
|
|||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div class="loginCard">
|
<div class="loginCard">
|
||||||
<mat-card class="matCard">
|
<mat-card class="matCard">
|
||||||
<div class="loginTitle">
|
<div class="loginTitle">
|
||||||
<div class="loginIcon">
|
<div class="loginIcon">
|
||||||
<mat-icon class="mat-icon-login" *ngIf="!isLightThemeEnabled" svgIcon="gns3"></mat-icon>
|
<mat-icon class="mat-icon-login" *ngIf="!isLightThemeEnabled" svgIcon="gns3"></mat-icon>
|
||||||
<mat-icon class="mat-icon-login" *ngIf="isLightThemeEnabled" svgIcon="gns3black"></mat-icon>
|
<mat-icon class="mat-icon-login" *ngIf="isLightThemeEnabled" svgIcon="gns3black"></mat-icon>
|
||||||
<div>
|
<div>
|
||||||
<h1>GNS3</h1>
|
<h1>GNS3</h1>
|
||||||
<h6>v{{version}}</h6>
|
<h6>v{{ version }}</h6>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form [formGroup]="loginForm">
|
|
||||||
<mat-form-field>
|
|
||||||
<input matInput formControlName="username" placeholder="Username" />
|
|
||||||
<mat-error *ngIf="loginForm.get('username').hasError('required')">You must enter username</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field>
|
|
||||||
<input matInput type="password" formControlName="password" placeholder="Password" />
|
|
||||||
<mat-error *ngIf="loginForm.get('password').hasError('required')">You must enter password</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div class="buttons-bar">
|
|
||||||
<button class="loginButton" mat-raised-button color="primary" (click)="login()">Login</button>
|
|
||||||
</div>
|
|
||||||
</mat-card>
|
|
||||||
|
|
||||||
<div class="errorMessage">
|
|
||||||
<mat-error *ngIf="loginError">Authentication was unsuccessful</mat-error>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form [formGroup]="loginForm">
|
||||||
|
<mat-form-field>
|
||||||
|
<input matInput formControlName="username" placeholder="Username" />
|
||||||
|
<mat-error *ngIf="loginForm.get('username').hasError('required')">You must enter username</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field>
|
||||||
|
<input matInput type="password" formControlName="password" placeholder="Password" />
|
||||||
|
<mat-error *ngIf="loginForm.get('password').hasError('required')">You must enter password</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<mat-checkbox
|
||||||
|
[disabled]="!isRememberMe"
|
||||||
|
[checked]="isRememberMeCheked"
|
||||||
|
class="margin-left"
|
||||||
|
color="primary"
|
||||||
|
(change)="rememberMe($event)"
|
||||||
|
>Remember me</mat-checkbox
|
||||||
|
>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button class="loginButton" mat-raised-button color="primary" (click)="login()">Login</button>
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
||||||
|
|
||||||
|
<div class="errorMessage">
|
||||||
|
<mat-error *ngIf="loginError">Authentication was unsuccessful</mat-error>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,8 +12,8 @@ mat-form-field {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mat-icon-login {
|
.mat-icon-login {
|
||||||
height: 100px!important;
|
height: 100px !important;
|
||||||
width: 100px!important;
|
width: 100px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loginTitle {
|
.loginTitle {
|
||||||
@ -35,3 +35,7 @@ mat-form-field {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.margin-left {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
@ -1,89 +1,123 @@
|
|||||||
import { Component, ComponentFactoryResolver, OnInit, ViewEncapsulation } from '@angular/core';
|
import { Component, DoCheck, OnInit, ViewEncapsulation } from '@angular/core';
|
||||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { AuthResponse } from '../../models/authResponse';
|
||||||
import { Server } from '../../models/server';
|
import { Server } from '../../models/server';
|
||||||
|
import { Version } from '../../models/version';
|
||||||
import { LoginService } from '../../services/login.service';
|
import { LoginService } from '../../services/login.service';
|
||||||
import { ServerDatabase } from '../../services/server.database';
|
import { ServerDatabase } from '../../services/server.database';
|
||||||
import { ServerService } from '../../services/server.service';
|
import { ServerService } from '../../services/server.service';
|
||||||
import { ToasterService } from '../../services/toaster.service';
|
|
||||||
import { AuthResponse } from '../../models/authResponse';
|
|
||||||
import { VersionService } from '../../services/version.service';
|
|
||||||
import { Version } from '../../models/version';
|
|
||||||
import { ThemeService } from '../../services/theme.service';
|
import { ThemeService } from '../../services/theme.service';
|
||||||
|
import { ToasterService } from '../../services/toaster.service';
|
||||||
|
import { VersionService } from '../../services/version.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-login',
|
selector: 'app-login',
|
||||||
templateUrl: './login.component.html',
|
templateUrl: './login.component.html',
|
||||||
styleUrls: ['./login.component.scss'],
|
styleUrls: ['./login.component.scss'],
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
})
|
})
|
||||||
export class LoginComponent implements OnInit {
|
export class LoginComponent implements OnInit, DoCheck {
|
||||||
private server: Server;
|
private server: Server;
|
||||||
public version: string;
|
public version: string;
|
||||||
public isLightThemeEnabled: boolean = false;
|
public isLightThemeEnabled: boolean = false;
|
||||||
public loginError: boolean = false;
|
public loginError: boolean = false;
|
||||||
public returnUrl: string = "";
|
public returnUrl: string = '';
|
||||||
|
public isRememberMe: boolean = false;
|
||||||
|
public isRememberMeCheked: boolean = false;
|
||||||
|
|
||||||
loginForm = new FormGroup({
|
loginForm = new FormGroup({
|
||||||
username: new FormControl('', [Validators.required]),
|
username: new FormControl('', [Validators.required]),
|
||||||
password: new FormControl('', [Validators.required])
|
password: new FormControl('', [Validators.required]),
|
||||||
|
});
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private loginService: LoginService,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private serverDatabase: ServerDatabase,
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private versionService: VersionService,
|
||||||
|
private themeService: ThemeService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get('server_id');
|
||||||
|
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
|
||||||
|
if (server.authToken) {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'projects']);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.versionService.get(this.server).subscribe((version: Version) => {
|
||||||
|
this.version = version.version;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
constructor(
|
this.themeService.getActualTheme() === 'light'
|
||||||
private loginService: LoginService,
|
? (this.isLightThemeEnabled = true)
|
||||||
private serverService: ServerService,
|
: (this.isLightThemeEnabled = false);
|
||||||
private serverDatabase: ServerDatabase,
|
|
||||||
private route: ActivatedRoute,
|
|
||||||
private router: Router,
|
|
||||||
private toasterService: ToasterService,
|
|
||||||
private versionService: VersionService,
|
|
||||||
private themeService: ThemeService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async ngOnInit() {
|
let getCurrentUser = JSON.parse(localStorage.getItem(`isRememberMe`)) ?? null;
|
||||||
const server_id = this.route.snapshot.paramMap.get('server_id');
|
if (getCurrentUser && getCurrentUser.isRememberMe) {
|
||||||
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
|
this.loginForm.get('username').setValue(getCurrentUser.username);
|
||||||
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
this.loginForm.get('password').setValue(getCurrentUser.password);
|
||||||
this.server = server;
|
this.isRememberMeCheked = getCurrentUser.isRememberMe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (server.authToken) {
|
public login() {
|
||||||
this.router.navigate(['/server', this.server.id, 'projects']);
|
if (this.loginForm.get('username').invalid || this.loginForm.get('password').invalid) {
|
||||||
}
|
this.toasterService.error('Please enter username and password');
|
||||||
|
return;
|
||||||
this.versionService.get(this.server).subscribe((version: Version) => {
|
|
||||||
this.version = version.version;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.themeService.getActualTheme() === 'light'
|
|
||||||
? (this.isLightThemeEnabled = true)
|
|
||||||
: (this.isLightThemeEnabled = false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public login() {
|
let username = this.loginForm.get('username').value;
|
||||||
if (this.loginForm.get('username').invalid || this.loginForm.get('password').invalid) {
|
let password = this.loginForm.get('password').value;
|
||||||
this.toasterService.error("Please enter username and password")
|
|
||||||
return;
|
this.loginService.login(this.server, username, password).subscribe(
|
||||||
|
async (response: AuthResponse) => {
|
||||||
|
let server = this.server;
|
||||||
|
server.authToken = response.access_token;
|
||||||
|
server.username = username;
|
||||||
|
server.password = password;
|
||||||
|
server.tokenExpired = false;
|
||||||
|
await this.serverService.update(server);
|
||||||
|
|
||||||
|
if (this.returnUrl.length <= 1) {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'projects']);
|
||||||
|
} else {
|
||||||
|
this.router.navigateByUrl(this.returnUrl);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
this.loginError = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let username = this.loginForm.get('username').value;
|
rememberMe(ev) {
|
||||||
let password = this.loginForm.get('password').value;
|
if (ev.checked) {
|
||||||
|
let curren_user = {
|
||||||
this.loginService.login(this.server, username, password).subscribe(async (response: AuthResponse) => {
|
username: this.loginForm.get('username').value,
|
||||||
let server = this.server;
|
password: this.loginForm.get('password').value,
|
||||||
server.authToken = response.access_token;
|
isRememberMe: ev.checked,
|
||||||
server.username = username;
|
};
|
||||||
server.password = password;
|
this.isRememberMeCheked = ev.checked;
|
||||||
await this.serverService.update(server);
|
localStorage.setItem(`isRememberMe`, JSON.stringify(curren_user));
|
||||||
|
} else {
|
||||||
if (this.returnUrl.length <= 1) {
|
localStorage.removeItem(`isRememberMe`);
|
||||||
this.router.navigate(['/server', this.server.id, 'projects'])
|
this.loginForm.reset();
|
||||||
} else {
|
this.isRememberMe = ev.checked;
|
||||||
this.router.navigateByUrl(this.returnUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
}, error => {
|
|
||||||
this.loginError = true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngDoCheck() {
|
||||||
|
if (this.loginForm.get('username').valid && this.loginForm.get('password').valid) {
|
||||||
|
this.isRememberMe = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,35 +6,20 @@ import { ServerService } from '../services/server.service';
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LoginGuard implements CanActivate {
|
export class LoginGuard implements CanActivate {
|
||||||
constructor(
|
constructor(private serverService: ServerService, private loginService: LoginService, private router: Router) {}
|
||||||
private serverService: ServerService,
|
|
||||||
private loginService: LoginService,
|
|
||||||
private router: Router
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
async canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||||
const server_id = next.paramMap.get('server_id');
|
const server_id = next.paramMap.get('server_id');
|
||||||
let server = await this.serverService.get(parseInt(server_id, 10));
|
this.loginService.server_id = server_id;
|
||||||
try {
|
let server = await this.serverService.get(parseInt(server_id, 10));
|
||||||
await this.loginService.getLoggedUser(server).toPromise();
|
try {
|
||||||
} catch (e) {
|
await this.loginService.getLoggedUser(server);
|
||||||
if (e.status === 401) {
|
} catch (e) {}
|
||||||
server.tokenExpired = true;
|
return this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
await this.serverService.update(server)
|
if (server.authToken && !server.tokenExpired) {
|
||||||
try {
|
return true;
|
||||||
let response = await this.loginService.login(server, server.username, server.password).toPromise();
|
}
|
||||||
server.authToken = response.access_token;
|
this.router.navigate(['/server', server.id, 'login'], { queryParams: { returnUrl: state.url } });
|
||||||
server.tokenExpired = false;
|
});
|
||||||
await this.serverService.update(server)
|
}
|
||||||
} catch (e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
|
||||||
if (server.authToken) return true;
|
|
||||||
this.router.navigate(['/server', server.id, 'login'], { queryParams: { returnUrl: state.url }});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,45 @@
|
|||||||
|
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpInterceptor, HttpEvent, HttpResponse, HttpRequest, HttpHandler } from '@angular/common/http';
|
import { LoginService } from '@services/login.service';
|
||||||
import { Observable } from 'rxjs';
|
import { ServerService } from '@services/server.service';
|
||||||
|
import { Observable, throwError } from 'rxjs';
|
||||||
|
import { catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class HttpRequestsInterceptor implements HttpInterceptor {
|
export class HttpRequestsInterceptor implements HttpInterceptor {
|
||||||
|
constructor(private serverService: ServerService, private loginService: LoginService) {}
|
||||||
intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
return next.handle(httpRequest);
|
return next.handle(httpRequest).pipe(
|
||||||
|
catchError((err) => {
|
||||||
|
if (err.status === 401 || err.status === 403) {
|
||||||
|
this.call();
|
||||||
|
} else {
|
||||||
|
return throwError(err);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async call() {
|
||||||
|
let getCurrentUser = JSON.parse(localStorage.getItem(`isRememberMe`)) ?? null;
|
||||||
|
const server_id = this.loginService.server_id;
|
||||||
|
let server = await this.serverService.get(parseInt(server_id, 10));
|
||||||
|
server.tokenExpired = true;
|
||||||
|
await this.serverService.update(server);
|
||||||
|
try {
|
||||||
|
if (getCurrentUser && getCurrentUser.isRememberMe) {
|
||||||
|
let response = await this.loginService.getLoggedUserRefToken(server, getCurrentUser);
|
||||||
|
server.authToken = response.access_token;
|
||||||
|
server.tokenExpired = false;
|
||||||
|
await this.serverService.update(server);
|
||||||
|
await this.loginService.getLoggedUser(server);
|
||||||
|
this.reloadCurrentRoute();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reloadCurrentRoute() {
|
||||||
|
location.reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import { AuthResponse } from '../models/authResponse';
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LoginService {
|
export class LoginService {
|
||||||
|
server_id:string =''
|
||||||
constructor(private httpServer: HttpServer) {}
|
constructor(private httpServer: HttpServer) {}
|
||||||
|
|
||||||
login(server: Server, username: string, password: string) {
|
login(server: Server, username: string, password: string) {
|
||||||
@ -22,6 +23,9 @@ export class LoginService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getLoggedUser(server: Server) {
|
getLoggedUser(server: Server) {
|
||||||
return this.httpServer.get(server, "/users/me");
|
return this.httpServer.get(server, "/users/me").toPromise()
|
||||||
|
}
|
||||||
|
async getLoggedUserRefToken(server: Server,current_user):Promise<any> {
|
||||||
|
return await this.httpServer.post<AuthResponse>(server, "/users/authenticate", {"username":current_user.username,"password":current_user.password}).toPromise()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user