我有一个反应式 Spring Boot 2 应用程序,它充当使用 Spring Security 启动用户身份验证的 Web 代理。访问此应用程序的最终用户来自公共或私有域,Web 代理应相应地将他们重定向到 Identity-Provider.com(公共)或 Identity-Provider.biz(私有)进行登录。 在两种情况下,redirect_uri 身份验证后保持相同。
我们在 application.yaml 中配置了 2 个 Oauth2 身份提供商和 2 个相应的 Oauth2 客户端。
spring:
security:
oauth2:
client:
provider:
idpcom:
issuer-uri: https://identity-provider.com
idpbiz:
issuer-uri: https://identity-provider.biz
registration:
idpcom:
provider: idpcom
client-id: clientid
client-secret: clientsecret
authorization-grant-type: authorization_code
redirect-uri: https://my-domain.com/login/oauth2/code/idpcom
scope:
- openid
idpbiz:
provider: idpbiz
client-id: clientid
client-secret: clientsecret
authorization-grant-type: authorization_code
redirect-uri: https://my-domain.com/login/oauth2/code/idpbiz
scope:
- openid
通过此配置,当应用程序收到请求时,最终用户会看到两个身份提供商的链接。用户被迫选择其中之一并启动身份验证流程。
我们发现 Spring security 中的以下代码正在构建上面所示的 HTML 页面
ServerHttpSecurity.setDefaultEntryPoints(ServerHttpSecurity http)
我们的要求是在运行时以编程方式解析身份提供者,并直接向最终用户显示相应的登录页面。使用identity-provider.com或identity-provider.biz的决定基于最终用户的IP地址(在X-Forwarded-For标头中捕获)。
我们需要建议来实现此功能。
根据手册,定义时
http.oauth2Login(oauth2 -> {
oauth2.loginPage("/login/oauth2");
});
您需要提供一个
以及能够呈现自定义登录页面的@Controller
。@RequestMapping("/login/oauth2")
你可以写这样的东西:
@Controller
public class LoginController {
private final Pattern internalIpsPattern;
public LoginController (@Value("internal-ips-pattern") String pattern) {
this.internalIpsPattern = Pattern.compile(pattern);
}
@GetMapping("/login/oauth2")
public RedirectView getAuthorizationCodeInitiationUrl(HttpServletRequest request) {
final var header = Optional.ofNullable(request.getHeader("X-Forwarded-For")).orElseThrow(() -> new MissingForwardedForException());
final var matcher = internalIpsPattern.matcher(header);
return matcher.matches() ? new RedirectView("/oauth2/authorization/idpbiz") : new RedirectView("/oauth2/authorization/idpcom");
}
@ResponseStatus(HttpStatus.UNAUTHORIZED)
static final class MissingForwardedForException extends RuntimeException {
private static final long serialVersionUID = 8215954933514492489L;
MissingForwardedForException() {
super("X-Forwarded-For header is missing");
}
}
}