Spring Boot 2.0.1 OAuth2对接Facebook时redirect_uri用http而非https的解决方法
我之前帮不少开发者处理过类似的场景,你的问题核心原因很明确——Spring没能正确识别当前请求的协议,尤其是当应用部署在反向代理(比如Nginx、Apache)后面时,代理先处理了HTTPS请求,再用HTTP转发给Spring应用,导致Spring误以为当前是HTTP环境,进而生成了HTTP协议的redirect_uri。
下面给你几个靠谱的解决方案,按优先级排序:
1. 配置Spring Boot识别转发头(最推荐)
如果你的应用在反向代理后面,首先要让Spring Boot读取代理传递的协议头,从而识别出真实的HTTPS协议。在application.properties或application.yml中添加以下配置:
# 启用转发头处理 server.use-forward-headers=true # 告诉Tomcat从X-Forwarded-Proto头获取真实协议 server.tomcat.protocol-header=x-forwarded-proto # 可选:获取真实客户端IP(非必须,但建议配置) server.tomcat.remote-ip-header=x-forwarded-for
同时,在Spring Security配置类中添加ForwardedHeaderFilter,确保请求头被优先处理:
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.core.Ordered; import org.springframework.web.filter.ForwardedHeaderFilter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.context.annotation.Configuration; @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { // 其他Security配置... @Bean public FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() { FilterRegistrationBean<ForwardedHeaderFilter> filterBean = new FilterRegistrationBean<>(); filterBean.setFilter(new ForwardedHeaderFilter()); // 设置最高优先级,确保转发头先被处理 filterBean.setOrder(Ordered.HIGHEST_PRECEDENCE); return filterBean; } }
配置完成后,Spring就能从代理传递的X-Forwarded-Proto头中识别出HTTPS协议,自动生成正确的redirect_uri。
2. 手动指定redirect_uri(直接有效)
如果第一种方法不生效,或者你想更直接地控制redirect_uri,可以在OAuth2客户端配置中硬指定HTTPS地址。
方式一:通过配置文件
在application.properties中直接配置Facebook客户端的redirect_uri:
spring.security.oauth2.client.registration.facebook.redirect-uri=https://你的域名.com/login/oauth2/code/facebook
记得替换成你实际的域名和回调路径。
方式二:通过Java代码配置
如果用代码定义ClientRegistration,可以直接指定redirectUriTemplate:
import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class OAuth2Config { @Bean public ClientRegistrationRepository clientRegistrationRepository() { return new InMemoryClientRegistrationRepository(facebookClient()); } private ClientRegistration facebookClient() { return ClientRegistration.withRegistrationId("facebook") .clientId("你的Facebook客户端ID") .clientSecret("你的Facebook客户端密钥") .redirectUriTemplate("https://你的域名.com/login/oauth2/code/facebook") .authorizationUri("https://www.facebook.com/v3.0/dialog/oauth") .tokenUri("https://graph.facebook.com/v3.0/oauth/access_token") .userInfoUri("https://graph.facebook.com/v3.0/me?fields=id,name,email") .userNameAttributeName("id") .clientName("Facebook") .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .clientAuthenticationMethod(ClientAuthenticationMethod.POST) .scope("public_profile", "email") .build(); } }
3. 检查Tomcat的SSL配置(直接部署Tomcat时)
如果你的应用是直接部署在独立Tomcat上(而非Spring Boot内嵌Tomcat),需要在Tomcat的server.xml中配置SSL连接器,并开启协议头识别:
<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" SSLEnabled="true"> <SSLHostConfig> <Certificate certificateKeystoreFile="conf/你的证书文件.jks" type="RSA"/> </SSLHostConfig> <!-- 添加RemoteIpValve识别转发的协议头 --> <Valve className="org.apache.catalina.valves.RemoteIpValve" protocolHeader="X-Forwarded-Proto" /> </Connector>
重要注意事项
别忘了在Facebook开发者后台的Valid OAuth Redirect URIs中,配置和你生成的redirect_uri完全一致的HTTPS地址,否则Facebook会直接拒绝认证请求。
内容的提问来源于stack exchange,提问作者Loreno Oliveira

