Я пытаюсь реализовать модуль для более крупного приложения, которое может получить доступ к данным пользователя с OID C. Проблема в том, что приложение действует как ретранслятор для множества клиентов, которые могут получить доступ к своему собственному серверу OID C, поэтому автоматическая настройка через application.properties не является приемлемой опцией. Аналогично, регистрация всех ClientRegistration
s в InMemoryClientRegistrationRepository
не является жизнеспособным вариантом, поскольку пользователи для клиента A могут не использовать ClientRegistration
для клиента B и наоборот.
В параграфе выше это уже показать большую часть моих знаний в этом вопросе:
- просто зарегистрировать до
n
ClientRegistration
объектов - всех зарегистрированных
ClientRegistration
объектов может будет автоматически определен Spring и будет доступен для выбора на странице входа в систему
Я уже "реализовал" ClientRegistrationRepository
примерно так:
@Service
public class MyCustomRepository implements ClientRegistrationRepository {
private final Map<String, ClientRegistration> registrations = new HashMap<>();
public MyCustomRepository() {
addDefaultRegistrations();
}
@Override
public ClientRegistration findByRegistrationId(String registrationId) {
return registrations.get(registrationId);
}
private void addDefaultRegistrations() {
// omitted
}
}
Это преднамеренно это не реализует Iterable<ClientRegistration>
по причинам, уже указанным. При использовании этой страницы, а не пользовательской страницы входа, страница входа по умолчанию пуста.
Если разрешено автоопределение ClientRegistration
s через Iterable
и при условии, что зарегистрирован только один ClientRegistration
, страница входа не отображается, вместо этого используется конечная точка авторизации <server>/login/oauth2/code/{registrationId}
.
Я пытаюсь повторить это поведение с помощью пользовательской страницы входа. Предполагается, что страница автоматически «решает», какую ClientRegistration следует использовать для инициации потока аутентификации.
Я попытался добавить пользовательский URL-адрес страницы входа с подстановочным знаком и переменной пути; оба не интерполируются, что приводит к неверным запросам входа в систему. Это имеет смысл, но я все же попробовал. Теперь у меня есть метод Controller, который принимает SPRING_SECURITY_SAVED_REQUEST
-атрибут, читает исходный URL и извлекает оттуда clientId, а затем отправляет перенаправление на соответствующую конечную точку:
@GetMapping("/doLogin")
public String login(
@SessionAttribute("SPRING_SECURITY_SAVED_REQUEST") SavedRequest originalRequest,
HttpServletResponse response) throws IOException {
String originalUrl = originalRequest.getRedirectUrl();
String[] parts = originalUrl.split("/");
String id = parts[parts.length - 1];
return "redirect:/login/oauth2/code/" + id;
}
Это, однако, прерывает обработка из-за «слишком большого количества запросов».
Edit 1
Я только что обнаружил, что «слишком много перенаправлений» происходит, потому что выбрасывается OAuth2AuthenticationException с сообщением «[invalid_request]» где-то. К сожалению, он нигде не появляется в моем стеке, и keycloak не регистрирует его, поэтому я не могу найти больше подробностей в atm.
Изменить 1 конец
Если я правильно понимаю страницу входа по умолчанию, она TECHNICALLY больше ничего не делает, за исключением того, что новый запрос запускается вместо «простого» перенаправления.
Поскольку каждый клиент может получить доступ только к одному ClientRegistration
объекту, выбор ДОЛЖЕН быть возможен без взаимодействия с пользователем.
Из того, что я собрал из документов, этот подход, строго говоря, не совсем неправильный, но определенно не правильный.
Итак, вопрос (ы) следующие:
- Может Я кодирую страницу входа, которая автоматически выберет «правильный» URL для запуска потока?
- Как я могу изменить свой подход, чтобы он мог делать то, что должен?
Примечание : будучи чрезвычайно хакерским, возможно использование шаблона тимелина с мгновенным перенаправлением, но я постараюсь избежать этого. Аналогично, создание начального URL-адреса аутентификации за пределами этого модуля возможно, но, скорее всего, не является жизнеспособным вариантом - если только я что-то пропустил.
Последнее замечание: при использовании одного объекта ClientRegistration вся связь работает из поле, поэтому проблема, как представляется, не на сервере. Я использую KeyCloak 9.0.0 в качестве поставщика OpenId.