我正在尝试为更大的应用程序实现一个模块,该模块可以使用OIDC访问用户数据。这里的挑战是该应用程序充当可能访问其自己的OIDC服务器的众多客户端的中继,因此通过application.properties自动配置不是一个可行的选择。
同样,在ClientRegistration中注册所有InMemoryClientRegistrationRepository也不可行,因为客户端A的用户可能不会对客户端B使用ClientRegistration,反之亦然。

在此问题上,以上段落已经证明了我的大部分知识:


注册最多n ClientRegistration个对象很简单
Spring可以自动检测所有已注册的ClientRegistration对象,并将在登录页面上对其进行选择


我已经像这样“实现”了一个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自动检测Iterable时,并且假设仅注册了一个ClientRegistration,则不会显示登录页面,而是直接使用授权端点<server>/login/oauth2/code/{registrationId}

我正在尝试用自定义登录“页面”复制此行为。
该页面应该自动“决定”应使用哪个ClientRegistration来启动身份验证流程。

我试图添加带有通配符和路径变量的自定义登录页面网址;两者均未插值,从而导致无效的登录请求。确实有道理,但是我还是尝试了。
现在,我有一个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;
    }


但是,由于“请求太多”而中断了处理。

编辑1
我刚刚发现发生“重定向过多”的原因是,某个地方抛出了带有消息“ [invalid_request]”的OAuth2AuthenticationException。不幸的是,它没有出现在我的堆栈中,keycloak也没有注册它,所以我找不到atm的更多详细信息。
编辑1个结束
如果我正确理解了默认的登录页面,则它在技术上无能为力,只是触发了一个新请求,而不是“简单”重定向。

由于每个客户端只能访问一个ClientRegistration对象,因此应该在没有用户交互的情况下进行选择。

从我从文档中收集的信息来看,严格地说,这种方法并不是完全错误的,但绝对不正确。

因此,问题如下:


我可以编写一个登录页面的代码,该页面将自动选择“正确的” URL以开始流程吗?
我如何修改我的方法,以便它可以做应做的事情?


注意:虽然极度骇客,但可以使用带有即时重定向的thymeleaf模板,但我会尽量避免这种情况。同样,可以在此模块外部构建身份验证开始URL,但很可能不是可行的选择-除非我错过了什么。

最后说明:使用单个ClientRegistration对象时,整个通信都是开箱即用的,
因此问题似乎不在服务器上。我正在使用KeyCloak 9.0.0作为OpenId提供程序。

最佳答案

一段时间后,我找到了解决方案和我的错误。
该方法确实可以正常工作,甚至必须使用正确的URL。
自定义登录页面必须-至少在我的情况下,不能直接重定向到过滤器URL,而应重定向到

/oauth2/authorize/{clientId}

这将启动该过程并按预期完成。

10-04 13:56