spring 处理 UserRedirectRequiredException(需要重定向才能获得用户批准)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32201870/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Handle UserRedirectRequiredException (A redirect is required to get the users approval)
提问by Cédric M.
Introduction
介绍
One week ago, I began the development of an application using the OAuth2 framework (with Spring Boot v1.3.0.M4). A brand new experience for me. So I try to make it as simple as possible to understand it better. I am using Spring Security OAuth2 and I am facing difficulties to use it correctly.
一周前,我开始使用 OAuth2 框架(使用 Spring Boot v1.3.0.M4)开发应用程序。对我来说是全新的体验。所以我尽量让它变得简单,以便更好地理解它。我正在使用 Spring Security OAuth2,但在正确使用它时遇到了困难。
What I want to do
我想做的事
Authenticate a user when this one authorize my application. Actually, I don't want him to register on my application so he can freely use it without having to fill boring forms to register.
当这个用户授权我的应用程序时,对用户进行身份验证。实际上,我不希望他在我的应用程序上注册,这样他就可以自由使用它而不必填写无聊的表格来注册。
Problem encountered
遇到的问题
I can't find a way to handle UserRedirectRequired Exception. Because I don't do it, the user is never redirected to the authorization page and an exception is thrown (and unhandled).
我找不到处理 UserRedirectRequired 异常的方法。因为我不这样做,所以用户永远不会被重定向到授权页面,并且会抛出异常(并且未处理)。
My application
我的应用程序
StandardController.java
标准控制器.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;
}
}
My problem
我的问题
When I get on my root application, Spring Security redirects me as I am not authenticated. It redirects me to the login page. Many exceptions are thrown and handled by the Spring Boot default configuration but when the UserRedirectRequiredException is created and thrown, no filter handles it. Debugging my application, I found that the last exception found by my oauth2ClientContextFilter is AccessDeniedException. I doubt that my filter (which is actually the OAuth2ClientContextFilter from the default configuration) is not correctly set in the filter chain.
当我进入我的根应用程序时,Spring Security 会重定向我,因为我没有经过身份验证。它将我重定向到登录页面。许多异常由 Spring Boot 默认配置抛出和处理,但是当 UserRedirectRequiredException 被创建和抛出时,没有过滤器处理它。调试我的应用程序时,我发现我的 oauth2ClientContextFilter 发现的最后一个异常是 AccessDeniedException。我怀疑我的过滤器(实际上是默认配置中的 OAuth2ClientContextFilter)没有在过滤器链中正确设置。
Stacktrace
堆栈跟踪
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]
Looking at the stacktrace, I tried to change the order of my filter in the filter chain. So I tried to put my OAuth2ClientContextFilter after the OAuth2ClientAuthenticationProcessingFilter. Unfortunately, when I launch the application, an error occurs telling me that the filter is unregistered.
查看堆栈跟踪,我尝试更改过滤器链中过滤器的顺序。所以我试图将我的 OAuth2ClientContextFilter 放在 OAuth2ClientAuthenticationProcessingFilter 之后。不幸的是,当我启动应用程序时,发生错误,告诉我过滤器未注册。
Change
改变
.addFilterAfter(oauth2ClientContextFilter, ExceptionTranslationFilter.class);
to
到
.addFilterAfter(oauth2ClientContextFilter, OAuth2ClientAuthenticationProcessingFilter.class);
Stacktrace
堆栈跟踪
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]
So I ask you to help me getting through this and get rid of this problem. I am aware that there are a lot of questions about this issue that are already answered but it couldn't help me as wanted.
所以我请你帮助我解决这个问题并摆脱这个问题。我知道有很多关于这个问题的问题已经得到回答,但它无法如愿以偿。
Thanking you for the time dedicated you took to help me.
感谢您花时间帮助我。
Cédric
塞德里克
回答by geg
An alternative to @Stilleur's solution is below. It is suggested in an official Spring guide under the heading "Handling the Redirects": https://spring.io/guides/tutorials/spring-boot-oauth2/
@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;
}
回答by Cédric M.
Changing .addFilterAfter(oauth2ClientContextFilter, ExceptionTranslationFilter.class);
to .addFilterAfter(oauth2ClientContextFilter, SecurityContextPersistenceFilter.class);
now makes the unhandled UserRedirectRequiredExceptiongetting handled.
更改.addFilterAfter(oauth2ClientContextFilter, ExceptionTranslationFilter.class);
为.addFilterAfter(oauth2ClientContextFilter, SecurityContextPersistenceFilter.class);
now 会使未处理的UserRedirectRequiredException得到处理。
回答by chendu
Refer to @geg 's answer, add @EnableOAuth2Client
is also available if you don't implement customer filter yourself.
请参阅@geg 的回答,@EnableOAuth2Client
如果您不自己实现客户过滤器,也可以添加。
Because the official demo says that @EnableOAuth2Client
also include a default filter for this.
因为官方演示说@EnableOAuth2Client
还包括一个默认过滤器。
Handling the Redirects
处理重定向
The last change we need to make is to explicitly support the redirects from our app to Facebook. This is handled in Spring OAuth2 with a servlet Filter, and the filter is already available in the application context because we used @EnableOAuth2Client. All that is needed is to wire the filter up so that it gets called in the right order in our Spring Boot application. To do that we need a FilterRegistrationBean:
我们需要做的最后一个更改是明确支持从我们的应用程序重定向到 Facebook。这是在 Spring OAuth2 中使用 servlet 过滤器处理的,并且过滤器在应用程序上下文中已经可用,因为我们使用了 @EnableOAuth2Client。所需要做的就是连接过滤器,以便在我们的 Spring Boot 应用程序中以正确的顺序调用它。为此,我们需要一个 FilterRegistrationBean:
回答by lmiguelmh
For those of you that have this problem in Weblogic: everything runs fine in the embedded Tomcat server but fails when using WebLogic. Assuming that you already configured the deployment in weblogic.xml (here is a nice example), you need to upgrade from WebLogic 12.1.2.0 to WebLogic 12.2.1.2. WL has some issues with libraries particularly with spring-security.
对于那些在 Weblogic 中遇到此问题的人:在嵌入式 Tomcat 服务器中一切正常,但在使用 WebLogic 时失败。假设您已经在 weblogic.xml 中配置了部署(这是一个很好的示例),您需要从 WebLogic 12.1.2.0 升级到 WebLogic 12.2.1.2。WL 在库方面存在一些问题,尤其是在 spring-security 方面。