Как программно выбрать ClientRegistration - PullRequest
0 голосов
/ 02 марта 2020

Я пытаюсь реализовать модуль для более крупного приложения, которое может получить доступ к данным пользователя с 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.

1 Ответ

0 голосов
/ 03 марта 2020

Через некоторое время я нашел решение и свою ошибку. Подход работает даже идеально, однако необходимо использовать правильные URL. Пользовательская страница входа должна - в моем случае, по крайней мере, не перенаправлять непосредственно на URL фильтра, а, скорее, на

/oauth2/authorize/{clientId}

, это запускает процесс и завершается, как и ожидалось.

...