小编典典

使用http而不是https的redirect_uri

spring-boot

我正在使用Spring堆栈(Spring Boot
2.0.1.RELEASE)创建一个站点,该站点通过OAuth2将用户身份验证/注册委托给Facebook。当我单击“使用Facebook登录”按钮时,我被重定向到Facebook,但是Spring
Security OAuth2正在使用http而不是https创建redirect_uri参数。该应用程序使用https,但我不知道此“ http”的来源。

那么,如何使Spring正确创建redirect_uri参数?

更新

抱歉,原来的帖子。已经很晚了,我想在睡觉前发布问题:-)

好了,我的应用程序使用了Spring Security 2.0.1.RELEASE和Spring Security OAuth2
5.0.4.RELEASE附带的Spring Boot
2.0.1.RELEASE。我的应用程序使用Facebook来注册和验证用户。目前,我有一个在AWS(Beanstalk)中运行并使用Amazon的SSL证书的测试环境。

当我第一次写帖子时,我的问题是我的应用程序(实际上是通过SS)发送给Facebook的redirect_uri参数具有一个HTTP前缀,而不是https。这在Facebook中导致错误,该错误仅接受https重定向URL。

阅读文档后,我发现了该spring.security.oauth2.client.registration.facebook.redirect-uri- template属性,并将其设置为https://[my domain]/login/oauth2/code/{registrationId}。现在,Facebook处理我的身份验证请求并将其发布回我的应用程序。

但是,使用先前的参数集,现在问题已改变。现在,当Facebook的回调在AWS上击中我的应用程序时,我将收到以下异常(来自日志):

2018-04-11 10:51:23 [http-nio-5000-exec-5] DEBUG o.s.s.o.c.w.OAuth2LoginAuthenticationFilter - Request is to process authentication
2018-04-11 10:51:23 [http-nio-5000-exec-5] DEBUG o.s.s.authentication.ProviderManager - Authentication attempt using org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationProvider
2018-04-11 10:51:23 [http-nio-5000-exec-5] DEBUG o.s.s.authentication.ProviderManager - Authentication attempt using org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider
2018-04-11 10:51:23 [http-nio-5000-exec-5] DEBUG o.s.s.o.c.w.OAuth2LoginAuthenticationFilter - Authentication request failed: org.springframework.security.oauth2.core.OAuth2AuthenticationException: [invalid_redirect_uri_parameter] 
org.springframework.security.oauth2.core.OAuth2AuthenticationException: [invalid_redirect_uri_parameter] 
    at org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationProvider.authenticate(OAuth2LoginAuthenticationProvider.java:117)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
    at org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter.attemptAuthentication(OAuth2LoginAuthenticationFilter.java:159)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.doFilterInternal(OAuth2AuthorizationRequestRedirectFilter.java:128)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)

查看源代码后,我发现问题似乎出在org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationProvider该类的以下测试中:

if (!authorizationResponse.getRedirectUri().equals(authorizationRequest.getRedirectUri())) {
    OAuth2Error oauth2Error = new OAuth2Error(INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE);
    throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}

为了检查为什么比较失败,我使用Chrome的开发者工具检查了请求和响应。因此,这是给Facebook的电话:

https://www.facebook.com/v2.8/dialog/oauth?response_type=code&client_id=[REMOVED]&scope=public_profile%20email&state=[REMOVED]&redirect_uri=https://[REMOVED]/login/oauth2/code/facebook

一切似乎正常,redirect_uri参数按预期使用https,并且完整的redirect_uri似乎正确。

这是Facebook的回调:

https://[REMOVED]/login/oauth2/code/facebook?code=[REMOVED]

再一次,一切似乎还好。但是,SS拒绝用户身份验证,因为请求和响应redirect_uris不匹配。

这就是问题。对这里出什么问题有任何想法吗?我想念什么吗?


阅读 715

收藏
2020-05-30

共1个答案

小编典典

我遇到了与Google完全相同的问题。

具有以下微服务架构

Google Auth Server


  Zuul Gateway (:8080)
     /   \
    /     \
   /       \
Other      OAuth2Client (:5000)

在本地计算机上运行时,一切正常,但是在AWS Elastic Beanstalk中,我捕获了相同的异常。

调试之后,我发现在我的情况下,当OAuth2Client位于Zuul代理(它们在单独的微服务中实现)后面时,我实际上在内部检查中获得了不同的redirect_uri值OAuth2LoginAuthenticationProvider

if (!authorizationResponse.getRedirectUri().equals(authorizationRequest.getRedirectUri())) {
    OAuth2Error oauth2Error = new OAuth2Error(INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE);
    throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}

因此,对于AWS,我具有以下值:

authorizationResponse.getRedirectUri()
http://[INNER_AWS_ESB_IP]:5000/auth/login/oauth2/code/google

authorizationRequest.getRedirectUri()
https://[MY_PROJECT_DOMAIN_NAME]/auth/login/oauth2/code/google

其中[INNER_AWS_ESB_IP],AWS Elastic
Beanstalk中的内部网络的IP地址[MY_PROJECT_DOMAIN_NAME]是我的项目的域名,该域名被硬编码application.ymlredirect-uri-template参数。

我有以下配置application.yml我的 OAuth2Client 的microService

server:
  port: 5000
  servlet:
     contextPath: /auth
  use-forward-headers: true

spring:
  security:
    oauth2:
      resource:
        filter-order: 3
      client:
        registration:
          google:
            client-id:  [REMOVED]
            client-secret: [REMOVED]
            redirect-uri-template: ${MY_PROJECT_DOMAIN_NAME:http://localhost:8080}/auth/login/oauth2/code/google
            scope: profile,email

洛雷诺,您拥有哪种建筑?您可以共享您的配置吗?

更新

似乎该问题与版本科学5.0中的Spring Security Oauth2 Client的实现直接相关

如果在某些单独的虚拟机上启动Zuul Gateway微服务而在本地计算机上启动其他微服务,则问题可以重现☝️因此,应从VM上的浏览器调用Google。

*帮助我避免此问题 *的解决方案 是添加Filter具有HttpServletRequestWrapper可覆盖方法的custom
的custom 并返回“正确的” URL以满足签入中的OAuth2LoginAuthenticationProvider.java:115要求。

  1. application.ymlOauth2客户端中

myCloudPath: ${MY_PROJECT_DOMAIN_NAME:http://localhost:8080}

  1. 在里面 SecurityConfig
@Value("${myCloudPath}")
private String myCloudPath;

@Override
public void configure(HttpSecurity http) throws Exception {
http.
     addFilterBefore(new MyCustomFilter(myCloudPath), OAuth2LoginAuthenticationFilter.class).
     ...
  1. 过滤

    public class MyCustomFilter implements Filter {
    
    private static final Logger logger = LogManager.getLogger(MyCustomFilter.class);
    private String myCloudPath;
    
    public MyCustomFilter(String myCloudPath) {
        this.myCloudPath= myCloudPath;
    }
    
    @Override
    public void init(FilterConfig filterConfiguration) throws ServletException {
        logger.info("MyCustomFilter init");
    }
    
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
    
        request = new MyHttpServletRequestWrapper((HttpServletRequest) request, myCloudPath);
    
        chain.doFilter(request, response);
    }
    
    @Override
    public void destroy() {
        logger.info("MyCustomFilter destroy");
    }
    

    }

  2. HttpServletRequestWrapper

    public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {
    
    public final String redirectUrl;
    
    public MyHttpServletRequestWrapper(HttpServletRequest request, String myCloudPath) {
        super(request);
        this.redirectUrl = myCloudPath + request.getRequestURI();
    }
    
    @Override
    public StringBuffer getRequestURL() {
        return new StringBuffer(redirectUrl);
    }
    

    }

2020-05-30