@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 или для realmId
Mock для тестов
Для удобства тестирования в setupTests
или в каждом тесте где это необходимо можно добавить:
import '@relotus/keycloak/src/mock';