Reputation: 13
im using Angular for a Project/Task management application with a user authentification. For this I set a JWT.
My problem, if the jwt is not valid any more or i destroy it in the local storage, im still able to navigate to the guardes routes and i the the for example user profil with empty fields. I recieve 500 or 401 from the backend, because the user is missing.
How can I check the current state of the jwt while navigating in the application?
app.component.ts:
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { TokenAuthService } from './shared/token-auth.service';
import { AuthenticationStateService } from './shared/authentication-state.service';
import { JwtService } from './shared/jwt.service';
import { User } from './user';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
isLoggedin: boolean | undefined;
user!: User;
constructor(
public router: Router,
private tokenAuthService: TokenAuthService,
public authenticationStateService: AuthenticationStateService,
public jwtService: JwtService
) {
if (this.isLoggedin){
this.jwtService.profile().subscribe((res:any) => {
this.user = res;
})
}
}
ngOnInit() {
this.authenticationStateService.userAuthState.subscribe(res => {
this.isLoggedin = res;
});
}
logOut() {
this.authenticationStateService.setAuthState(false);
this.tokenAuthService.destroyToken();
this.router.navigate(['signin']);
}
}
authentication-state.service.ts
import { Injectable } from '@angular/core';
import { TokenAuthService } from '../shared/token-auth.service';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
@Injectable({
providedIn: 'root'
})
export class AuthenticationStateService {
private userCurrentState = new BehaviorSubject<boolean | undefined>(this.tokenAuthService.isSignedin());
userAuthState = this.userCurrentState.asObservable();
constructor(
public tokenAuthService: TokenAuthService
) { }
setAuthState(value: boolean) {
this.userCurrentState.next(value);
}
}
login.guard.ts
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
import { User } from '../user';
import { AuthenticationStateService } from './authentication-state.service';
import { JwtService } from './jwt.service';
@Injectable({
providedIn: 'root'
})
export class LoginGuard implements CanActivate, CanActivateChild {
isLoggedin: boolean | undefined;
user!: User;
constructor(
public authenticationStateService: AuthenticationStateService,
public jwtService: JwtService
) {
this.jwtService.profile().subscribe((res:any) => {
this.user = res;
})
this.authenticationStateService.userAuthState.subscribe(res => {
this.isLoggedin = res;
});
}
ngOnInit() {
}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
if(this.isLoggedin==true){
return true;
console.log('eingeloggt');
}else {
return false;
console.log('ausgeloggt');
}
}
canActivateChild(
childRoute: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return true;
}
}
token-auth.service.ts
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { environment } from 'src/environments/environment';
@Injectable({
providedIn: 'root'
})
export class TokenAuthService {
private tokenIssuer = {
login: environment.apiUrl + '/api/auth/signin',
register: environment.apiUrl + '/api/auth/signup'
}
constructor(
public router: Router,
) { }
setTokenStorage(token: string){
localStorage.setItem('auth_token', token);
}
getJwtToken(){
return localStorage.getItem('auth_token');
}
// Validate token
validateToken(){
const token = this.getJwtToken();
if(token){
const payload = this.payload(token);
if(payload){
return Object.values(this.tokenIssuer).indexOf(payload.iss) > -1 ? true : false;
}else {
return false;
}
} else {
return false;
}
}
payload(token: string) {
const jwtPayload = token.split('.')[1];
return JSON.parse(atob(jwtPayload));
}
// User state
isSignedin() {
return this.validateToken();
}
// Destroy token
destroyToken(){
localStorage.removeItem('auth_token');
}
}
Upvotes: 1
Views: 356
Reputation: 13
I updated the "validateToken" and "isSignedin". They didnt work. It seems to work now
public isAuthenticated(): boolean {
const token = localStorage.getItem('auth_token');
if (token) {
if(this.jwtHelper.isTokenExpired(token)){
return false;
}
return true;
}else{
return false;
}
}
Upvotes: 0
Reputation: 64
2 things: First: Have you set de guard in the routes canActivate property? For example:
{ path: 'tasks', component: TaskListComponent, canActivate: [LoginGuard] },
Second: don't you need to redirect the user to /login if isloggedIn is false?
For example:
if(this.isLoggedin==true){
return true;
console.log('eingeloggt'); // code after return will not run!!
}else {
this.router.navigate('/login'); // you need to have this route in your routes
return false;
console.log('ausgeloggt'); // code after return will not run!!
Upvotes: 1