/
Al
/
TESamples
Обзор
Документация
Войти
/
Al
/
TESamples
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
apps/spring/bff-agent/src/main/java/com/tokenexchange/bff/KcAdminClient.java
74 строки
3 KB
Al
Initial Commit
11 май 2026, 17:40
11 май 2026, 17:40
0a04577
Код
Авторство
О чём код?
package com.tokenexchange.bff; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestClient; /** * Минимальный Keycloak Admin REST client для FR-05.2: logout user'а. * * Phase 7 / S5: BFF, получив запрос «отозвать полномочия агента», вызывает * {@code POST /admin/realms/{realm}/users/{id}/logout}. Это запускает SPI * (event-listener-redis) → Redis pub/sub → deny-list во всех chain-сервисах. */ @Component public class KcAdminClient { private static final Logger log = LoggerFactory.getLogger(KcAdminClient.class); private final RestClient http; private final IdpRouter idpRouter; private final String adminUser; private final String adminPassword; public KcAdminClient( RestClient http, IdpRouter idpRouter, @Value("${KC_ADMIN_USERNAME:admin}") String adminUser, @Value("${KC_ADMIN_PASSWORD:admin-dev}") String adminPassword ) { this.http = http; this.idpRouter = idpRouter; this.adminUser = adminUser; this.adminPassword = adminPassword; } public void logoutUser(String userId) { IdpRouter.IdpEndpoint ep = idpRouter.primary(); // Admin-токен из realm master: String masterUrl = ep.baseUrl() + "/realms/master/protocol/openid-connect/token"; MultiValueMap<String, String> form = new LinkedMultiValueMap<>(); form.add("grant_type", "password"); form.add("client_id", "admin-cli"); form.add("username", adminUser); form.add("password", adminPassword); AdminToken at = http.post() .uri(masterUrl) .contentType(MediaType.APPLICATION_FORM_URLENCODED) .body(form) .retrieve() .body(AdminToken.class); if (at == null || at.accessToken() == null) { throw new IllegalStateException("Failed to get admin token"); } String url = ep.baseUrl() + "/admin/realms/" + ep.realm() + "/users/" + userId + "/logout"; http.post() .uri(url) .header("Authorization", "Bearer " + at.accessToken()) .retrieve() .toBodilessEntity(); log.info("Triggered Keycloak logout for user {} (realm={})", userId, ep.realm()); } @JsonIgnoreProperties(ignoreUnknown = true) public record AdminToken(@JsonProperty("access_token") String accessToken) {} }