Я защищаю свое приложение Angular 6 токенами JWT.У меня есть служба аутентификации для защиты элементов пользовательского интерфейса:
export class AuthService {
constructor(
private http: HttpClient,
private router: Router,
public jwtHelper: JwtHelperService,
) {}
isAuthenticated(): boolean {
return !this.isTokenExpired;
}
, которую я затем могу вызвать в своих компонентах:
<span class="page-nav" *ngIf="!authService.isAuthenticated()">
<a mat-button routerLink="/login">
Log In
</a>
</span>
У меня также есть защита аутентификации для моих маршрутов:
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(): boolean {
if (!this.authService.isAuthenticated()) {
this.router.navigate(['/login']);
return false;
}
return true;
}
}
Это все работает нормально, за исключением случаев, когда токен становится недействительным, тогда текущая страница не перенаправляется на login
.
Например, если я вхожу в систему, получаю действительный токен JWT, яможет перейти на защищенную страницу, и появляются защищенные элементы интерфейса (навигация и т. д.)Если я затем удаляю токен JWT из локального хранилища с помощью инструментов разработчика Chrome и нажимаю на навигацию, защищенные элементы пользовательского интерфейса исчезают, как и ожидалось, но защищенная страница остается, средство проверки подлинности маршрута не вызывается и только направляется на login
при переходе на другую страницу.
Я пробовал маршрутизацию в методе isAuthenticated()
authService, но это вызывает бесконечный цикл.Как я могу автоматически направить на login
вне вызова AuthGuard?
EDIT
маршрутизация:
const routes: Routes = [
{ path: '', redirectTo: '/products', pathMatch: 'full' },
{
path: 'products',
component: ProductsComponent,
canActivate: [AuthGuard],
children: [
{ path: ':id', component: ProductComponent, canActivate: [AuthGuard] },
],
},
{
path: 'search',
component: SearchComponent,
canActivate: [AuthGuard],
},
{ path: 'login', component: LoginComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
EDIT : я понимаю, что это ожидаемое поведение, поскольку @GangadharJannu упоминает , маршрутизатор не знает, что элементы пользовательского интерфейса вызвали метод isAuthenticated()
и теперь скрыты, поскольку он возвращает false
До тех пор, пока метод обновления AuthService не будет вызван и не выполнит ту же проверку.Мне интересно узнать, как лучше всего сообщить маршрутизатору, чтобы он переходил к login
, когда элементы пользовательского интерфейса вызывают метод isAuthenticated()
?
РЕДАКТИРОВАТЬ: мое рабочее решение:
import { map } from 'rxjs/operators';
import { interval } from 'rxjs';
import { JwtHelperService } from '@auth0/angular-jwt';
...
public validateToken(): void {
interval(1000).pipe(
map(() => {
const isExpired: boolean = this.jwtHelper.isTokenExpired(
localStorage.getItem('jwt_token'),
);
if (isExpired) {
this.logout();
}
}),
);
}