Spring Security OAuth2 重定向循环

7
我有一个oauth2客户端spring-boot应用程序,依赖项为: - spring-boot 1.2.0.RC1 - spring-security-oauth2 2.0.4.RELEASE - spring-security 3.2.5.RELEASE
客户端进行身份验证,身份验证设置在SecurityContextHolder中,但当请求重定向到原始URL时,过滤器链会再次开始处理。我注意到在SecurityContextPersistenceFilter中,contextBeforeChainExecution和contextAfterChainExecution都具有空身份验证。
我基于[1]Spring Security OAuth2 (google) web app in redirect loop的一些代码。
有什么想法为什么会出现重定向循环?谢谢您的帮助。
[日志片段]https://gist.github.com/yterradas/61da3f6eccc683b3a086 以下是安全配置。
@Configuration
public class SecurityConfig {
@Configuration @EnableWebMvcSecurity protected static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired private OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationProcessingFilter;
@Autowired private LoginUrlAuthenticationEntryPoint vaultAuthenticationEntryPoint;
@SuppressWarnings({"SpringJavaAutowiringInspection"}) @Autowired private OAuth2ClientContextFilter oAuth2ClientContextFilter;
@Override protected void configure(HttpSecurity http) throws Exception { // 禁用匿名访问,只允许已认证用户访问 http .authorizeRequests() .antMatchers("/**").authenticated() .and() .exceptionHandling().authenticationEntryPoint(vaultAuthenticationEntryPoint) .and() // 添加过滤器 .addFilterAfter(oAuth2ClientContextFilter, ExceptionTranslationFilter.class) .addFilterBefore(oAuth2ClientAuthenticationProcessingFilter, FilterSecurityInterceptor.class) .anonymous().disable(); }
@Override public void configure(WebSecurity web) throws Exception { // 禁用调试模式 web /* TODO: disable debug in production */ .debug(true); } }
@Configuration @EnableOAuth2Client protected static class ClientSecurityConfig {
@Value("${app.name}") private String appId; @Value("${app.clientId}") private String appClientId; @Value("${app.clientSecret}") private String appClientSecret; @Value("${app.redirectUrl}") private String appRedirectUrl; @Value("${vault.accessTokenUrl}") private String vaultAccessTokenUrl; @Value("${vault.userAuthorizationUrl}") private String vaultUserAuthorizationUrl; @Value("${vault.checkTokenUrl}") private String vaultCheckTokenUrl;
@SuppressWarnings({"SpringJavaAutowiringInspection"}) @Resource @Qualifier("oauth2ClientContext") private OAuth2ClientContext oAuth2ClientContext;
@Autowired @Qualifier("securityDataSource") private DataSource securityDataSource;
@Autowired private MappingJackson2HttpMessageConverter jackson2HttpMessageConverter;
// 创建 OAuth2RestOperations 实例 @Bean public OAuth2RestOperations oAuth2RestOperations() { AccessTokenProviderChain provider = new AccessTokenProviderChain( Arrays.asList(new AuthorizationCodeAccessTokenProvider()) ); provider.setClientTokenServices(new JdbcClientTokenServices(securityDataSource));
OAuth2RestTemplate template = new OAuth2RestTemplate(oAuth2Resource(), oAuth2ClientContext); template.setAccessTokenProvider(provider); template.setMessageConverters(Arrays.asList(jackson2HttpMessageConverter));
return template; }
// 创建 OAuth2ProtectedResourceDetails 实例 @Bean OAuth2ProtectedResourceDetails oAuth2Resource() { AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
resource.setId(appId); resource.setAuthenticationScheme(AuthenticationScheme.query); resource.setAccessTokenUri(vaultAccessTokenUrl); resource.setUserAuthorizationUri(vaultUserAuthorizationUrl); resource.setUseCurrentUri(false); resource.setPreEstablishedRedirectUri(appRedirectUrl); resource.setClientId(appClientId); resource.setClientSecret(appClientSecret); resource.setClientAuthenticationScheme(AuthenticationScheme.form);
return resource; }
// 创建 ResourceServerTokenServices 实例 @Bean ResourceServerTokenServices oAuth2RemoteTokenServices() { VaultTokenServices tokenServices = new VaultTokenServices();
RestTemplate restOperations = new RestTemplate(); restOperations.setMessageConverters(Arrays.asList(jackson2HttpMessageConverter));
tokenServices.setRestTemplate(restOperations); tokenServices.setClientId(appClientId); tokenServices.setClientSecret(appClientSecret); tokenServices.setCheckTokenEndpointUrl(vaultCheckTokenUrl);
return tokenServices; }
// 创建 OAuth2ClientAuthenticationProcessingFilter 实例 @Bean OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationProcessingFilter() { OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter("/vaultLogin");
filter.setRestTemplate(oAuth2RestOperations()); filter.setTokenServices(oAuth2RemoteTokenServices());
return filter; }
} }

授权服务器在哪里?它的检查令牌端点是否可用(您可以使用curl吗)? - Dave Syer
授权服务器是一个独立的组件,不在同一个项目中。是的,我可以使用curl。我可以看到授权被创建,以及重定向到保存请求被启动。我不确定,但我认为上下文没有被保存。之所以这样想,是因为执行前后的上下文都没有身份验证。 - Yoandy Terradas
我特别问了一下,你是否可以使用curl命令访问/check_token端点。这不是规范的一部分,因此根据实现方式,它可能存在也可能不存在(而你的客户端似乎正在尝试使用它)。 - Dave Syer
@DaveSyer 是的,我可以使用curl。此外,我有一个自定义的RemoteTokenServices来处理验证,因为授权服务器不使用http-basic进行验证。我已经在问题中更新了日志片段。也许这可以帮助解决问题。 - Yoandy Terradas
3个回答

2

我认为你有两个OAuth2ClientContextFilters(一个是由@EnableOAuth2Client添加的,另一个是你手动添加到Spring Security过滤器链中的)。你应该能够删除你添加的那一个。


我已经从Spring Security过滤器链中删除了OAuth2ClientContextFilter,但仍然存在重定向循环。请告诉我可以提供哪些其他信息。 - Yoandy Terradas

0

对于可能遇到相同问题的其他人——在使用Spring Security oAuth时出现重定向循环。我之所以遇到这个问题是因为我身处防火墙之后,防火墙会禁止直接访问互联网,而我的Spring Boot+Security应用需要调用位于互联网上的IdP的userinfo端点,例如Okta、Google等。您可以通过在本地运行配置中配置您的代理来解决这个问题,方法如下:

-Dhttp.proxyHost=yourhttpproxy.company.com 
-Dhttp.proxyPort=yourhttproxyport
-Dhttp.nonProxyHosts=”localhost|*.yourintranetdomain1.com|*.yourintranetdomain2.com|etc” 
-Dhttps.proxyHost=yourhttpsproxy.company.com
-Dhttps.proxyPort=yourhttpsproxyport 
-Dhttps.nonProxyHosts=”localhost|*.yourintranetdomain1.com|*.yourintranetdomain2.com|etc”

希望这能有所帮助。


0

我找到了一个平庸的解决方案,它涉及从SecurityFilterChain中删除几乎所有过滤器。不幸的是,我没有我所工作的应用程序的工作副本。然而,通过在破坏应用程序之前尽可能删除许多过滤器,然后仅添加必要的过滤器,应该很容易复制该解决方案。如果我的记忆没有出错,罪魁祸首可能是SecurityContextPersistenceFilterRequestCacheAwareFilter


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接