java - Spring Boot OAuth 始终重定向到 HTTP (IBM Cloud CF + Spring Boot 2)
问题描述
在 IBM Cloud CF Java Buildpack 上使用 Spring Boot OAuth 2...
https://github.com/ericis/oauth-cf-https-issue
*我已经尝试了以下每种组合。
使用此配置,应用程序陷入无限的重定向循环,OAuth 重定向策略将其发送到http
,然后此配置将其发送到https
.
http.requiresChannel().anyRequest().requiresSecure()
如果没有此配置,用户可以通过 http 登录(不需要)。
完整配置:
http.
requiresChannel().anyRequest().requiresSecure().
authorizeRequests().
// allow access to...
antMatchers("favicon.ico", "/login", "/loginFailure", "/oauth2/authorization/ghe")
.permitAll().anyRequest().authenticated().and().oauth2Login().
// Codify "spring.security.oauth2.client.registration/.provider"
clientRegistrationRepository(this.clientRegistrationRepository()).
// setup OAuth2 client service to use clientRegistrationRepository
authorizedClientService(this.authorizedClientService()).
successHandler(this.successHandler()).
// customize login pages
loginPage("/login").failureUrl("/loginFailure").
userInfoEndpoint().
// customize the principal
userService(this.userService());
我也试过:
要使用的服务器配置
https
server: useForwardHeaders: true tomcat: protocolHeader: x-forwarded-proto
Servlet 过滤器
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class HttpToHttpsFilter implements Filter { private static final Logger log = LoggerFactory.getLogger(HttpToHttpsFilter.class); private static final String HTTP = "http"; private static final String SCHEME_HTTP = "http://"; private static final String SCHEME_HTTPS = "https://"; private static final String LOCAL_ID = "0:0:0:0:0:0:0:1"; private static final String LOCALHOST = "localhost"; @Value("${local.ip}") private String localIp; public HttpToHttpsFilter() { // Sonar } @Override public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) req; final HttpServletResponse response = (HttpServletResponse) res; // http, not localhost, not localhost ipv6, not local IP if (HTTP.equals(request.getScheme()) && !LOCALHOST.equals(request.getRemoteHost()) && !LOCAL_ID.equals(request.getRemoteHost()) && (this.localIp != null && !this.localIp.equals(request.getRemoteHost()))) { final String query = request.getQueryString(); String oldLocation = request.getRequestURL().toString(); if (query != null) { oldLocation += "?" + query; } final String newLocation = oldLocation.replaceFirst(SCHEME_HTTP, SCHEME_HTTPS); try { log.info("HTTP redirect from {} to {} ", oldLocation, newLocation); response.sendRedirect(newLocation); } catch (IOException e) { log.error("Cannot redirect to {} {} ", newLocation, e); } } else { chain.doFilter(req, res); } } @Override public void destroy() { // Sonar } @Override public void init(FilterConfig arg0) throws ServletException { // Sonar } }
依赖项
dependencies {
//
// BASICS
// health and monitoring
// compile('org.springframework.boot:spring-boot-starter-actuator')
// security
compile('org.springframework.boot:spring-boot-starter-security')
// configuration
compile('org.springframework.boot:spring-boot-configuration-processor')
//
// WEB
// web
compile('org.springframework.boot:spring-boot-starter-web')
// thymeleaf view render
compile('org.springframework.boot:spring-boot-starter-thymeleaf')
// thymeleaf security extras
compile('org.thymeleaf.extras:thymeleaf-extras-springsecurity4')
//
// OAUTH
// OAuth client
compile('org.springframework.security:spring-security-oauth2-client')
// OAuth lib
compile('org.springframework.security:spring-security-oauth2-jose')
// OAuth config
compile('org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.0.0.RELEASE')
//
// CLOUD
// cloud connectors (e.g. vcaps)
compile('org.springframework.boot:spring-boot-starter-cloud-connectors')
//
// TOOLS
runtime('org.springframework.boot:spring-boot-devtools')
//
// TEST
// test
testCompile('org.springframework.boot:spring-boot-starter-test')
// security test
testCompile('org.springframework.security:spring-security-test')
}
解决方案
这已解决。有关与此相关的问题的详细信息,请参见: https ://github.com/spring-projects/spring-security/issues/5535#issuecomment-407413944
现在正在运行的示例项目:https ://github.com/ericis/oauth-cf-https-issue
简短的回答:
应用程序需要显式配置以了解代理标头。我尝试过配置,但最终不得不使用ForwardedHeaderFilter
最近添加到 Spring 的类的实例。
@Bean
FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
final FilterRegistrationBean<ForwardedHeaderFilter> filterRegistrationBean = new FilterRegistrationBean<ForwardedHeaderFilter>();
filterRegistrationBean.setFilter(new ForwardedHeaderFilter());
filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return filterRegistrationBean;
}
推荐阅读
- promise - Dexie toArray() 承诺
- haskell - Haskell:了解函数的副作用
- javascript - 需要使用 javascript/jQuery 从购物车中添加和删除项目
- postgresql - Postgresql 如何提高大型连接表排序的性能?
- jenkins - 在 Jenkins 中运行的 csh 的 $#argv 错误
- php - 在 Mac OS X 上将 ldap 驱动程序加载到 MAMP 上
- mysql - Mysql优化日期过滤器
- excel - 为什么我的更改事件代码未处理?
- reactjs - React 本机应用程序不会填满整个屏幕
- sql - 转换十进制值时出现转换错误。精度更高的记录没有转换