redirect after login works now
This commit is contained in:
5
hv2-ui/package-lock.json
generated
5
hv2-ui/package-lock.json
generated
@ -6725,6 +6725,11 @@
|
|||||||
"set-immediate-shim": "~1.0.1"
|
"set-immediate-shim": "~1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jwt-decode": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A=="
|
||||||
|
},
|
||||||
"karma": {
|
"karma": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/karma/-/karma-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/karma/-/karma-5.1.1.tgz",
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
"@angular/platform-browser": "~11.0.6",
|
"@angular/platform-browser": "~11.0.6",
|
||||||
"@angular/platform-browser-dynamic": "~11.0.6",
|
"@angular/platform-browser-dynamic": "~11.0.6",
|
||||||
"@angular/router": "~11.0.6",
|
"@angular/router": "~11.0.6",
|
||||||
|
"jwt-decode": "^3.1.2",
|
||||||
"rxjs": "~6.6.0",
|
"rxjs": "~6.6.0",
|
||||||
"tslib": "^2.0.0",
|
"tslib": "^2.0.0",
|
||||||
"zone.js": "~0.10.2"
|
"zone.js": "~0.10.2"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
import { AuthGuardService } from './auth-guard.service';
|
||||||
import { LoginComponent } from './login/login.component';
|
import { LoginComponent } from './login/login.component';
|
||||||
import { LogoutComponent } from './logout/logout.component';
|
import { LogoutComponent } from './logout/logout.component';
|
||||||
import { TestOutputComponent } from './test-output/test-output.component';
|
import { TestOutputComponent } from './test-output/test-output.component';
|
||||||
@ -7,7 +8,7 @@ import { TestOutputComponent } from './test-output/test-output.component';
|
|||||||
|
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: 'test', component: TestOutputComponent },
|
{ path: 'test', component: TestOutputComponent, canActivate: [ AuthGuardService ] },
|
||||||
{ path: 'logout', component: LogoutComponent },
|
{ path: 'logout', component: LogoutComponent },
|
||||||
{ path: 'login', component: LoginComponent }
|
{ path: 'login', component: LoginComponent }
|
||||||
]
|
]
|
||||||
|
16
hv2-ui/src/app/auth-guard.service.spec.ts
Normal file
16
hv2-ui/src/app/auth-guard.service.spec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AuthGuardService } from './auth-guard.service';
|
||||||
|
|
||||||
|
describe('AuthGuardService', () => {
|
||||||
|
let service: AuthGuardService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(AuthGuardService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
22
hv2-ui/src/app/auth-guard.service.ts
Normal file
22
hv2-ui/src/app/auth-guard.service.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
|
||||||
|
import { MessageService } from './message.service';
|
||||||
|
import { TokenService } from './token.service';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class AuthGuardService implements CanActivate {
|
||||||
|
|
||||||
|
constructor(public tokenService: TokenService, public router: Router, private messageService: MessageService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||||
|
this.messageService.add(`Activated: ${next.url}`)
|
||||||
|
if (! this.tokenService.checkAuthenticated()) {
|
||||||
|
return this.router.parseUrl(`/login?returnUrl=${next.url}`)
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,7 +21,7 @@ export class ErrorHandlerInterceptor implements HttpInterceptor {
|
|||||||
catchError((errorResponse: HttpErrorResponse) => {
|
catchError((errorResponse: HttpErrorResponse) => {
|
||||||
this.messageService.add(`Intercepted http error: ${JSON.stringify(errorResponse, undefined, 4)}`)
|
this.messageService.add(`Intercepted http error: ${JSON.stringify(errorResponse, undefined, 4)}`)
|
||||||
if (errorResponse.status === 401) {
|
if (errorResponse.status === 401) {
|
||||||
this.router.navigateByUrl('/login')
|
this.router.navigate(['login'])
|
||||||
}
|
}
|
||||||
return throwError(errorResponse)
|
return throwError(errorResponse)
|
||||||
})
|
})
|
||||||
|
@ -22,7 +22,7 @@ export class LoginComponent implements OnInit {
|
|||||||
private tokenService: TokenService,
|
private tokenService: TokenService,
|
||||||
private messageService: MessageService) {
|
private messageService: MessageService) {
|
||||||
this.returnUrl = this.route.snapshot.queryParams.returnUrl || '/'
|
this.returnUrl = this.route.snapshot.queryParams.returnUrl || '/'
|
||||||
|
this.messageService.add(`Return URL is ${this.returnUrl}`)
|
||||||
this.form = this.fb.group({
|
this.form = this.fb.group({
|
||||||
username: ['', Validators.required],
|
username: ['', Validators.required],
|
||||||
password: ['', Validators.required]
|
password: ['', Validators.required]
|
||||||
@ -30,6 +30,9 @@ export class LoginComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
if (this.tokenService.checkAuthenticated()) {
|
||||||
|
this.router.navigate([this.returnUrl])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async onSubmit(): Promise<void> {
|
async onSubmit(): Promise<void> {
|
||||||
@ -40,6 +43,7 @@ export class LoginComponent implements OnInit {
|
|||||||
const username = this.form.get('username')?.value;
|
const username = this.form.get('username')?.value;
|
||||||
const password = this.form.get('password')?.value;
|
const password = this.form.get('password')?.value;
|
||||||
await this.tokenService.login(username, password);
|
await this.tokenService.login(username, password);
|
||||||
|
this.router.navigate([this.returnUrl])
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.messageService.add(`Login err: ${err.message}`)
|
this.messageService.add(`Login err: ${err.message}`)
|
||||||
this.loginInvalid = true;
|
this.loginInvalid = true;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
import { MessageService } from '../message.service';
|
import { MessageService } from '../message.service';
|
||||||
import { TokenService } from '../token.service';
|
import { TokenService } from '../token.service';
|
||||||
|
|
||||||
@ -9,11 +10,11 @@ import { TokenService } from '../token.service';
|
|||||||
})
|
})
|
||||||
export class LogoutComponent implements OnInit {
|
export class LogoutComponent implements OnInit {
|
||||||
|
|
||||||
constructor(private messageService: MessageService) { }
|
constructor(private tokenService: TokenService, private router: Router, private messageService: MessageService) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
localStorage.removeItem(TokenService.Id_Token_Key)
|
this.tokenService.logout()
|
||||||
this.messageService.add("Token removed from local storage")
|
this.router.navigateByUrl('/login')
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import { Component } from '@angular/core';
|
|||||||
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
|
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { map, shareReplay } from 'rxjs/operators';
|
import { map, shareReplay } from 'rxjs/operators';
|
||||||
|
import { TokenService } from '../token.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-navigation',
|
selector: 'app-navigation',
|
||||||
@ -10,12 +11,18 @@ import { map, shareReplay } from 'rxjs/operators';
|
|||||||
})
|
})
|
||||||
export class NavigationComponent {
|
export class NavigationComponent {
|
||||||
|
|
||||||
|
public authenticated: boolean
|
||||||
|
|
||||||
isHandset$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset)
|
isHandset$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset)
|
||||||
.pipe(
|
.pipe(
|
||||||
map(result => result.matches),
|
map(result => result.matches),
|
||||||
shareReplay()
|
shareReplay()
|
||||||
);
|
);
|
||||||
|
|
||||||
constructor(private breakpointObserver: BreakpointObserver) {}
|
constructor(private breakpointObserver: BreakpointObserver, private tokenService: TokenService) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.authenticated = this.tokenService.checkAuthenticated()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ import { Injectable } from '@angular/core';
|
|||||||
import { MessageService } from './message.service';
|
import { MessageService } from './message.service';
|
||||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
import { UserCreds } from './userCreds'
|
import { UserCreds } from './userCreds'
|
||||||
import { ThrowStmt } from '@angular/compiler';
|
import jwt_decode from 'jwt-decode'
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
@ -11,14 +12,28 @@ export class TokenService {
|
|||||||
public static Id_Token_Key : string = "id_token";
|
public static Id_Token_Key : string = "id_token";
|
||||||
|
|
||||||
constructor(private http: HttpClient, private messageService: MessageService) {
|
constructor(private http: HttpClient, private messageService: MessageService) {
|
||||||
this.messageService.add("TokenService started, token created")
|
|
||||||
|
|
||||||
if (! localStorage.getItem(TokenService.Id_Token_Key)) {
|
|
||||||
localStorage.setItem(TokenService.Id_Token_Key, "abc")
|
|
||||||
this.messageService.add("Token set in local storage")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkAuthenticated(): boolean {
|
||||||
|
let result: boolean = false
|
||||||
|
|
||||||
|
const token = localStorage.getItem(TokenService.Id_Token_Key)
|
||||||
|
if (token) {
|
||||||
|
let expiration = jwt_decode(token)["exp"]
|
||||||
|
if ((expiration * 1000) > Date.now()) {
|
||||||
|
result = true
|
||||||
|
} else {
|
||||||
|
this.logout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
localStorage.removeItem(TokenService.Id_Token_Key)
|
||||||
|
this.messageService.add("Token removed from local storage")
|
||||||
|
}
|
||||||
|
|
||||||
async login(login: string, password: string) {
|
async login(login: string, password: string) {
|
||||||
this.messageService.add(`TokenService: trying to login and obtain token`);
|
this.messageService.add(`TokenService: trying to login and obtain token`);
|
||||||
@ -32,7 +47,6 @@ export class TokenService {
|
|||||||
userCreds,
|
userCreds,
|
||||||
{responseType:'text'}
|
{responseType:'text'}
|
||||||
).toPromise()
|
).toPromise()
|
||||||
this.messageService.add(`Token is ${token}`)
|
|
||||||
localStorage.setItem(TokenService.Id_Token_Key, token)
|
localStorage.setItem(TokenService.Id_Token_Key, token)
|
||||||
this.messageService.add("Token saved")
|
this.messageService.add("Token saved")
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user