使用 spring-security-oauth2 的 SSO:从未读取身份验证代码

SSO using spring-security-oauth2 : Authentication Code never read

使用:

我有一个使用 spring-security-oauth (oauth2) 构建的可用 oauth2 提供程序。

我将客户端配置为使用 authorization_code 授权类型。

提供商完美运行: 使用 curl 进行测试,我可以获得授权码并将其交换为访问令牌。 所以在服务提供商方面,一切都很好。

现在我正在尝试实现客户端应用程序,也使用 spring-security-oauth。 我正在使用 xml 配置,强烈基于示例 here,但使用我自己的提供程序(上面提到的)而不是 google。

当我调用客户端上的受保护资源时,OAuth2ClientAuthenticationProcessingFilter 会尝试获取访问令牌,因此它会重定向到我的服务提供商。那一个强制用户按预期登录,然后将他重定向到配置的 redirect_uri(重定向 uri 是为我的 OAuth2ClientAuthenticationProcessingFilter 配置的:类似于 http://myClient/context/external/login)。 问题是:客户端从未读取服务提供商返回的请求中的授权码。因此 OAuth2ClientAuthenticationProcessingFilter 重新启动流程,请求授权码。

我已经能够通过修改 OAuth2ClientAuthenticationProcessingFilter 来读取请求并在 AccessTokenRequest 中设置授权代码来使其工作。这是片段:

OAuth2AccessToken accessToken;
try {
  String code = request.getParameter("code");
  if(code != null) {
    restTemplate.getOAuth2ClientContext().getAccessTokenRequest().setAuthorizationCode(code);
  }
  accessToken = restTemplate.getAccessToken();
  ...

在尝试此操作之前,我尝试在方法 org.springframework.security.oauth2.client.token.AccessTokenRequest.setAuthorizationCode() 上创建一个 "call hierarchy",以查找代码中 spring 调用该方法的位置,但它没有返回任何内容。

这是一个错误吗? 我真的不想用我自己的替换 OAuth2ClientAuthenticationProcessingFilter

是否有人让它工作(在那个版本或另一个版本中)?

更新

这是从未调用的 setAuthorizationCode() 方法(我最初的问题中的错误)。但我进一步挖掘,发现这不是问题所在。

我可以断言 OAuth2ClientContextFilterOAuth2ClientAuthenticationProcessingFilter 之前调用(我用调试器检查过)。

我发现了什么,但不知道是否正常:

DefaultAccessTokenRequest 的默认构造函数仅调用一次:在应用程序启动时。另一个构造函数(采用参数映射的构造函数)永远不会被调用。因为我在 RestTemplateBeanDefinitionParser 中看到访问令牌请求的范围是 'request',所以我希望在对我的客户端应用程序的每个新 http 请求上调用采用参数映射的构造函数。 在 RestTemplateBeanDefinitionParser 中:

BeanDefinitionBuilder request = BeanDefinitionBuilder.genericBeanDefinition(DefaultAccessTokenRequest.class);
request.setScope("request");
request.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
request.addConstructorArgValue("#{request.parameterMap}");
request.addPropertyValue("currentUri", "#{request.getAttribute('currentUri')}");

这可以解释我从未从请求中读取授权代码的问题。我在最初的问题中提到的黑客只是推迟了问题。现在我收到 csrf 保护错误,因为 AccessTokenRequest 总是记得一些 stateKey 当我认为一旦我获得访问令牌就不再需要它时。

再一次,也许我只是误解了这个洞的想法,所以请随时告诉我:)

我没有 post 我的配置,因为它与 that one here 非常相同。

您需要一个 OAuth2ClientContextFilter 并且它需要在身份验证处理过滤器之前触发(它基本上完成您在自定义过滤器中拥有的那些东西)。我无法从您发布的代码中判断您是否有一个但它没有触发或者您没有。

对花费宝贵时间帮助我的所有人表示抱歉。我过于专注于调试,以至于错过了一个配置问题。 永远不要像这样配置 Oauth2RestTemplate

<beans:bean id="myRestTemplate" class="org.springframework.security.oauth2.client.OAuth2RestTemplate">
     <beans:constructor-arg ref="myResourceId"/>
</beans:bean>

这解释了为什么 DefaultAccessTokenRequest 不是请求范围的,因此调用的是默认控制器,而不是获取请求参数映射的控制器。 不要像我一样使用 xml 命名空间! :

<oauth:rest-template id="myRestTemplate" resource="myResourceId"/>

仍然想知道我为什么这样做:P