我正在尝试为更大的应用程序实现一个模块,该模块可以使用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}
这将启动该过程并按预期完成。