一周前,我开始使用OAuth2框架(使用Spring Boot v1.3.0.M4)开发应用程序。对我来说是全新的体验。因此,我尝试使其尽可能简单以更好地理解它。我正在使用Spring Security OAuth2,并且在正确使用它方面遇到困难。
我想做的事
当此人授权我的应用程序时,对用户进行身份验证。实际上,我不希望他在我的应用程序上注册,因此他可以自由使用它,而不必填写无聊的表格进行注册。
遇到的问题
我找不到处理UserRedirectRequired异常的方法。因为我不这样做,所以永远不会将用户重定向到授权页面,并且会引发(并处理)异常。
StandardController.java
package org.test.oauth.web; import java.security.Principal; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController public class StandardController { @RequestMapping(value = "/", method = RequestMethod.GET) public String getHelloWorld() { return "Hello world !"; } @RequestMapping(value = "/user", method = RequestMethod.GET) public Principal getUser(Principal principal) { return principal; } }
StandardConfiguration.java
package org.test.oauth.configuration; import java.util.Arrays; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.oauth2.client.OAuth2ClientContext; import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter; import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails; import org.springframework.security.web.access.ExceptionTranslationFilter; @Configuration @EnableOAuth2Sso public class StandardConfiguration extends WebSecurityConfigurerAdapter { @Autowired private OAuth2ClientContextFilter oauth2ClientContextFilter; @Autowired private OAuth2ClientContext oauth2ClientContext; @Override protected void configure(HttpSecurity http) throws Exception { // @formatter:off http .authorizeRequests().antMatchers("/login").anonymous().and() .authorizeRequests().anyRequest().authenticated().and() .httpBasic().and() .addFilterAfter(oauth2ClientContextFilter, ExceptionTranslationFilter.class); // @formatter:on } // org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.security.oauth2.client.OAuth2RestOperations] is defined: expected single matching bean but found 2: restTemplate,userInfoRestTemplate // @Bean // public OAuth2RestOperations restTemplate() { // return new OAuth2RestTemplate(bnetResource(), oauth2ClientContext); // } @Bean public OAuth2ProtectedResourceDetails bnetResource() { AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails(); resource.setId("bnet"); resource.setClientId("***"); resource.setClientSecret("***"); resource.setAccessTokenUri("https://eu.battle.net/oauth/token"); resource.setUserAuthorizationUri("https://eu.battle.net/oauth/authorize"); resource.setScope(Arrays.asList("wow.profile")); return resource; } }
当我进入根应用程序时,由于我未通过身份验证,Spring Security会将我重定向。它将我重定向到登录页面。Spring Boot默认配置会引发和处理许多异常,但是当创建并引发UserRedirectRequiredException时,没有过滤器会处理它。在调试应用程序时,我发现由oauth2ClientContextFilter找到的最后一个异常是AccessDeniedException。我怀疑我的过滤器(实际上是默认配置中的OAuth2ClientContextFilter)在过滤器链中设置不正确。
堆栈跟踪
org.springframework.security.oauth2.client.resource.UserRedirectRequiredException: A redirect is required to get the users approval at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.getRedirectForAuthorization(AuthorizationCodeAccessTokenProvider.java:347) ~[spring-security-oauth2-2.0.7.RELEASE.jar:na] at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAccessToken(AuthorizationCodeAccessTokenProvider.java:194) ~[spring-security-oauth2-2.0.7.RELEASE.jar:na] at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221) ~[spring-security-oauth2-2.0.7.RELEASE.jar:na] at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173) ~[spring-security-oauth2-2.0.7.RELEASE.jar:na] at org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:94) ~[spring-security-oauth2-2.0.7.RELEASE.jar:na] at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:96) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.23.jar:8.0.23] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.23.jar:8.0.23] at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
查看堆栈跟踪,我试图更改过滤器链中过滤器的顺序。因此,我尝试将OAuth2ClientContextFilter放在OAuth2ClientAuthenticationProcessingFilter之后。不幸的是,当我启动该应用程序时,发生错误,告诉我该过滤器未注册。
更改
.addFilterAfter(oauth2ClientContextFilter, ExceptionTranslationFilter.class);
至
.addFilterAfter(oauth2ClientContextFilter, OAuth2ClientAuthenticationProcessingFilter.class);
2015-08-25 12:05:50.990 ERROR 9132 --- [ost-startStop-1] o.s.b.c.embedded.tomcat.TomcatStarter : Error starting Tomcat context: org.springframework.beans.factory.UnsatisfiedDependencyException 2015-08-25 12:05:51.054 WARN 9132 --- [ main] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt java.lang.IllegalArgumentException: Cannot register after unregistered Filter class org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter at org.springframework.security.config.annotation.web.builders.FilterComparator.registerAfter(FilterComparator.java:145) ~[spring-security-config-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.springframework.security.config.annotation.web.builders.HttpSecurity.addFilterAfter(HttpSecurity.java:960) ~[spring-security-config-4.0.2.RELEASE.jar:4.0.2.RELEASE] at org.test.oauth.configuration.StandardConfiguration.configure(StandardConfiguration.java:36) ~[classes/:na] at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.getHttp(WebSecurityConfigurerAdapter.java:199) ~[spring-security-config-4.0.2.RELEASE.jar:4.0.2.RELEASE] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_45]
因此,请您帮助我解决这个问题并摆脱这个问题。我知道关于此问题有很多问题已得到解答,但并不能按需要帮助我。
感谢您花费时间为我提供帮助。
塞德里克
@Stilleur解决方案的替代方法如下。它在Spring官方指南中的“处理重定向”标题下建议:https : //spring.io/guides/tutorials/spring-boot- oauth2/
@Bean public FilterRegistrationBean oauth2ClientFilterRegistration( OAuth2ClientContextFilter filter) { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(filter); registration.setOrder(-100); return registration; }