@relotus/keycloak v1.0.1
@relotus/keycloak
Описание
@relotus/keycloak - npm-пакет для работы авторизации в корпоративном Keycloak
Подключение в проект
Установка:
npm install @relotus/keycloakПример использования
Для использования Keycloak в приложении его необходимо проинициализировать:
import { initKeycloak } from '@relotus/keycloak';
const KeycloakProvider = initKeycloak({
  url: config.AUTH_HTTP,
  realm: config.AUTH_REALM,
  clientId: config.AUTH_CLIENT_ID,
});KeycloakProvider - это компонент, в которое необходимо обернуть приложение для работы хуков из этого пакета.
ВАЖНО
Если в вашем проекте используется
ResetErrorBoundaryиз@relotus/utkonos, то он должен быть ребенком дляKeycloakProvider, а не наоборот:<KeycloakProvider onUserLogin={login} onUserLogOut={logout}> <ErrorBoundary> <Provider store={store}>{appContent}</Provider> </ErrorBoundary> </KeycloakProvider>В противном случае это приведет к тому, что в случае ошибки будет бесконечный редирект в Keycloak
Установка токена для запросов
Для упрощения работы с токеном, вы можете при вызове initKeycloak передать Аxios и для него будет установлен интерцептор:
import { initKeycloak } from '@relotus/keycloak';
const KeycloakProvider = initKeycloak(config, axios);Теперь для каждого запроса будет добавлен заголовок Authorization со значением Bearer ${keycloak.token}.
Если в вашем приложении используется адаптер поверх Axios то можно использовать функцию bindInterceptor. Функция возвращает функцию, вызов которой уберет интерцептор.
import { initKeycloak } from '@relotus/keycloak';
import { bindInterceptor } from '@relotus/keycloak/src/interceptor';
const KeycloakProvider = initKeycloak(config, axios);
const { keycloak } = KeycloakProvider;
class Api {
  private _axios: AxiosInstance;
  private removeInterceptor: () => void;
  constructor() {
    this._axios = axios.create({
      baseURL: `${config.API_BASE_URL}/web`,
      paramsSerializer: formatParams,
    });
    this.removeInterceptor = bindInterceptor(this._axios, keycloak);
  }
}Обработка событий
Есть несколько способов обработать события авторизации:
- Самый простой - пробросить в KeycloakProvider обработчики для событий авторизации и завершения сессии: - import { initKeycloak } from '@relotus/keycloak'; const KeycloakProvider = initKeycloak(config, axios); function App() { const handleLogin = useCallback((profile: KeycloakProfile) => {}, []); const handleLogout = useCallback(() => {}, []); return ( <KeycloakProvider onUserLogin={handleLogin} onUserLogOut={handleLogout}> <MyApp /> </KeycloakProvider> ); }
- Использовать chanel для саги - import { createKeycloakChannel, events } '@relotus/keycloak/src/saga'; function* saga() { const keycloakChannel = yield call(createKeycloakChannel) try { while (true) { let keycloakEvent = yield take(keycloakChannel) if(events.authSuccess(keycloakEvent)){ // обрабатываем авторизацию; const { payload } = keycloakEvent } } } finally { if (yield cancelled()) { keycloakChannel.close() } } }
- Для всех остальных случаев есть возможность подписаться на - AuthClientEventнапрямую:- import { initKeycloak } from '@relotus/keycloak'; const KeycloakProvider = initKeycloak(config, axios); const eventName: AuthClientEvent = 'onAuthSuccess'; const unsubscribe = KeycloakProvider.subscribe( eventName, ({ keycloak, error }: { error?: AuthClientError; keycloak: KeycloakInstance }) => { // Обрабатываем событие }, ); // Отписываемся unsubscribe();
Получение доступа к Keycloak
Для получения доступа в компонентах можно использовать хук useKeycloak:
import { useKeycloak } from '@relotus/keycloak';
const { keycloak } = useKeycloak();
const logout = useCallback(() => {
  keycloak.logout().catch(() => {
    /* обрабатываем ошибку */
  });
}, [toggleDetails]);Вне компонентов, например для вызова Keycloak#logout():
const { keycloak } = KeycloakProvider;
keycloak.logout().catch(() => {
  /* обрабатываем ошибку */
});Проверка ролей
ВАЖНО
Роли настраиваются для
clientIdилиrealmIdв админке Keycloak
Для проверки ролей в компоненте можно использовать хук useHasRole
import { useHasRole } from '@relotus/keycloak';
function Component() {
  const hasAdminRole = useHasRole('ADMIN');
  return hasAdminRole ? 'Я админ' : 'Я пользователь';
}Хук проверяет как роли для для clientId, так и для realmId.
Вне компонента можно воспользоваться вызовом методов hasRealmRole (проверка роли для realmId) или hasResourceRole (проверка роли для clientId)
const isRealmManager = keycloak.hasRealmRole('MANAGER');
const isClientHasAccessToDictionaries = keycloak.hasResourceRole('Dictionaries.READ');Для проверки роли можно воспользоваться утилитой hasRole:
import { hasRole } from '@relotus/keycloak/src/utils';
const { keycloak } = KeycloakProvider;
const hasAdminRole = hasRole(keycloak, 'ADMIN'); // Имеет роль ADMIN для clientId или для realmIdMock для тестов
Для удобства тестирования в setupTests или в каждом тесте где это необходимо можно добавить:
import '@relotus/keycloak/src/mock';