我有一个带有依赖项的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的一些代码
有关为什么重定向循环的任何想法?先感谢您 .
[Logs snippet] 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 {
// @formatter:off
http
.authorizeRequests()
.antMatchers("/**").authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(vaultAuthenticationEntryPoint)
.and()
.addFilterAfter(oAuth2ClientContextFilter, ExceptionTranslationFilter.class)
.addFilterBefore(oAuth2ClientAuthenticationProcessingFilter, FilterSecurityInterceptor.class)
.anonymous().disable();
// @formatter:on
}
@Override
public void configure(WebSecurity web) throws Exception {
// @formatter:off
web
/* TODO:
disable debug in production
*/
.debug(true);
// @formatter:on
}
}
@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;
@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;
}
@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;
}
@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;
}
@Bean
LoginUrlAuthenticationEntryPoint oAuth2AuthenticationEntryPoint() {
return new LoginUrlAuthenticationEntryPoint("/vaultLogin");
}
@Bean
OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationProcessingFilter() {
OAuth2ClientAuthenticationProcessingFilter filter =
new OAuth2ClientAuthenticationProcessingFilter("/vaultLogin");
filter.setRestTemplate(oAuth2RestOperations());
filter.setTokenServices(oAuth2RemoteTokenServices());
return filter;
}
}
}
3 回答
我找到了一个平庸的解决方案,它需要从SecurityFilterChain中删除几乎所有的过滤器 . 不幸的是,我没有我工作的应用程序的工作副本 . 但是,通过在打破应用程序之前删除尽可能多的过滤器然后只添加必要的过滤器来复制解决方案应该很容易 . 如果内存为我提供服务,那么罪魁祸首就是SecurityContextPersistenceFilter或RequestCacheAwareFilter .
对于其他可能带来相同问题的人来说 - 使用Spring Security oAuth时的重定向循环 . 我有这个,因为我在阻止任何直接访问Internet的防火墙后面,我的Spring Boot Security应用程序需要调用位于Internet上的IdP的userinfo endpoints ,例如Okta,Google等您可以通过在本地运行配置中配置代理来修复它,如下所示:
我希望这有帮助 .
我认为你有2
OAuth2ClientContextFilters
(一个是由@EnableOAuth2Client
添加的,你已经手动添加了另一个到Spring Security过滤器链) . 您应该能够删除您添加的那个 .