
Веб-токены JSON (JWT) — это популярная стратегия аутентификации, используемая в веб-приложениях для безопасной передачи информации между сторонами в виде объектов JSON.
Аутентификация JWT работает следующим образом: когда пользователь входит в систему, сервер генерирует JWT и отправляет его клиенту. Затем клиент сохраняет JWT, обычно в локальном хранилище или в файле cookie, и включает его в заголовок последующих запросов к серверу. Затем сервер проверяет подпись JWT, декодирует полезную нагрузку и использует информацию в полезной нагрузке для аутентификации и авторизации пользователя.
На мой взгляд, реализовать стратегию аутентификации JWT несложно, за исключением одной сложной части — стратегии токена обновления. Поскольку веб-токен JSON имеет срок действия, у клиента должен быть механизм для запроса нового токена после того, как запрос вернет статус 401 «Неавторизованный». По сути это будет работать так:

Когда клиент получает ответ о статусе 401, он должен запросить новый токен доступа, а затем повторить исходный ответ с новым токеном.
Такое поведение может быть сложно реализовать, особенно если вы обрабатываете состояние аутентификации с помощью библиотеки хранилища, такой как NgRx или Redux.
В этой статье я покажу, как реализовать эту стратегию с помощью Angular и NgRx, и поделюсь репозиторием шаблонов GitHub, который включает в себя проект с JWT-аутентификацией, реализованный в бэкэнде NestJs, вместе с настройкой Nx Monorepo, готовой для повышения вашего нового полноценный проект.
Я не буду делиться здесь всем кодом, только основные части, вместо этого, если вы хотите заглянуть глубже, вам следует просмотреть репозиторий GitHub.
Во-первых, нужно определить форму состояния авторизации, и это просто, это будут просто два строковых поля, подобные этому:
interface AuthInfo {
accessToken: string;
refreshToken: string;
}
Затем нам нужно будет использовать функцию Angular HTTP Interceptors, чтобы поймать ошибку запроса 401, вы должны принять во внимание, что следующий код — это способ, которым я бы его реализовал, но если у вас есть другое мнение, не стесняйтесь, дайте мне знать.
По сути, внутри HTTP-перехватчика нам нужно будет выбрать информацию об аутентификации в хранилище, и когда он имеет токен, отличный от того, что был в исходном запросе, это означает, что запрос токена обновления завершен и он был успешным, и тогда мы можем повторить запрос с новым токеном доступа, код будет выглядеть следующим образом:
function refreshTokenInterceptor(req, next) {
return next(req).pipe(
catchError((err) => {
if (err.status === 401) {
// refresh the token
return of(store.dispatch(AuthActions.refreshTokenRequest())).pipe(
switchMap(() => store.select(AuthFeature.selectAuthInfo)),
// only emits when the store has the new accessToken
first(
(info) =>
info.accessToken !==
req.headers.get("authorization")?.split(" ")[1]
),
switchMap((info) => {
// clone the request and return a new observable to the switch map operator
return next(
req.clone({
headers: req.headers.set(
"Authorization",
`Bearer ${info.accessToken}`
),
})
);
})
);
}
return of(err)
})
)
}
Взглянув на вкладку сети браузера, вы заметите, что стратегия токена обновления работает должным образом.

Надеюсь, эта статья окажется полезной, как и репозиторий шаблонов GitHub.