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