Angular 6 JWT аутентификация - PullRequest
0 голосов
/ 10 октября 2018

Я защищаю свое приложение 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();
        }
      }),
    );
  }

1 Ответ

0 голосов
/ 10 октября 2018

У нас было родительское пустое состояние только для защиты защищенной части нашего приложения, вы можете попробовать это.Попробуйте выполнить настройку маршрутизации, подобную этой:

const routes: Routes = [{ 
    path: '', 
    canActivateChild: [AuthGuard], 
    runGuardsAndResolvers: 'always',
    children: [{
        path: 'products',
        component: ProductsComponent,
        children: [
          { path: ':id', component: ProductComponent },
        ],
      }, {
        path: 'search',
        component: SearchComponent
    }]
  },
  { path: '', redirectTo: '/products', pathMatch: 'full' },
  { path: 'login', component: LoginComponent },
];

Notice runGuardsAndResolvers: 'always' - это указывает angular всегда запускать охранников и распознавателей даже при переходе в одно и то же состояние.

Edit

Таким образом, в основном вы хотите наблюдать за локальным хранилищем и реагировать на изменения, поэтому, когда токен удаляется из хранилища или срок его действия истекает, вы хотите сразу перейти к компоненту входа в систему.Некоторые идеи:

  • Вы можете увеличить частоту проверки срока действия до 1 с, это не повредит, так как в настоящее время вы проверяете, истек ли токен каждый цикл рендеринга
  • , который вы можете настроитьвремя, которое можно наблюдать каждый раз, когда токен обновляется, поэтому он срабатывает через одну секунду после истечения срока действия и переходит к логину
  • , чтобы наблюдать за изменениями в самом локальном хранилище, вы можете найти библиотеку, имеющую эту функцию (, как этоодин ) или просто используйте событие изменения собственного хранилища напрямую
  • , если вам не нужен случай использования, когда пользователь удаляет токен вручную, тогда вы можете перейти к входу в систему, когда ваше приложениеудаляет токен из локального хранилища ( вопрос / ответы )
...