java 尽管定义了 RequestContextListener,但创建名为“scopedTarget.oauth2ClientContext”的 bean 时出错

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/48921897/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 10:12:25  来源:igfitidea点击:

Error creating bean with name 'scopedTarget.oauth2ClientContext' despite defining RequestContextListener

javaspringspring-securityspring-security-oauth2

提问by tryingToLearn

My app has multiple spring security configurations and one of them happens to be Oauth2(using thiseaxmple).

我的应用程序有多个 spring 安全配置,其中一个恰好是Oauth2(使用这个eaxmple)。

Spring security in general is getting plugged in via:

Spring 安全一般是通过以下方式插入的:

ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);             
context.addFilter(GzipFilter.class, "/*", EnumSet.allOf(DispatcherType.class));
context.addFilter(new FilterHolder( new DelegatingFilterProxy( DEFAULT_FILTER_NAME ) ), "/*",EnumSet.allOf( DispatcherType.class ));
AnnotationConfigWebApplicationContext securityContext = new AnnotationConfigWebApplicationContext();
securityContext.setConfigLocation("com.test.auth");
DispatcherServlet dispatcherServlet = new DispatcherServlet(securityContext);
context.addServlet(new ServletHolder(dispatcherServlet), "/");
context.addServlet(new ServletHolder(new ServletContainer(createResourceConfig(AuthController.class))), "/auth/*");

Oauth2 which looks like this:

Oauth2 看起来像这样:

@Order(4)
@EnableOAuth2Client
@EnableWebSecurity
@Configuration  
public class Oauth2Config extends WebSecurityConfigurerAdapter {    
        @Bean
        @Order(0)
        public RequestContextListener requestContextListener() {
            return new RequestContextListener();
        }

        @Autowired
        private OAuth2ClientContext oauth2ClientContext;

        @Autowired
        private OAuth2ClientContextFilter oauth2ClientContextFilter;

        @Autowired
        private AuthConfig authConfig;

        private OAuth2ProtectedResourceDetails authorizationCodeResource() {
            AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();

            details.setId("google-oauth-client");
            details.setClientId(authConfig.getProperty("oauth2.clientId"));
            details.setClientSecret(authConfig.getProperty("oauth2.clientSecret"));
            details.setUserAuthorizationUri(authConfig.getProperty("oauth2.userAuthorizationUri"));
            details.setAccessTokenUri(authConfig.getProperty("oauth2.accessTokenUri"));
            details.setTokenName(authConfig.getProperty("oauth2.tokenName"));
            details.setScope(Arrays.asList(authConfig.getPropertyList("oauth2.scope")));

            details.setAuthenticationScheme(AuthenticationScheme.query);
            details.setClientAuthenticationScheme(AuthenticationScheme.form);
            return details;
        }     



        @Bean
        public OAuth2ClientAuthenticationProcessingFilter
                    oauth2ClientAuthenticationProcessingFilter() {
            // Used to obtain access token from authorization server (AS)
            OAuth2RestOperations restTemplate = new OAuth2RestTemplate(
                    authorizationCodeResource(),
                    oauth2ClientContext);
            OAuth2ClientAuthenticationProcessingFilter filter =
                    new OAuth2ClientAuthenticationProcessingFilter(authConfig.getProperty("oauth2.filterCallbackPath"));
            filter.setRestTemplate(restTemplate);
            // Set a service that validates an OAuth2 access token
            // We can use either Google API's UserInfo or TokenInfo
            // For this, we chose to use UserInfo service
            filter.setTokenServices(googleUserInfoTokenServices());
            return filter;
        }

        @Bean           
        public GoogleUserInfoTokenServices googleUserInfoTokenServices() {
            GoogleUserInfoTokenServices userInfoTokenServices =
                    new GoogleUserInfoTokenServices(authConfig.getProperty("oauth2.userInfoUri"), authConfig.getProperty("oauth2.clientId"));
            // TODO Configure bean to use local database to read authorities
            // userInfoTokenServices.setAuthoritiesExtractor(authoritiesExtractor);
            return userInfoTokenServices;
        }

        @Bean
        public AuthenticationEntryPoint authenticationEntryPoint() {
            // May need an OAuth2AuthenticationEntryPoint for non-browser clients
            return new LoginUrlAuthenticationEntryPoint(authConfig.getProperty("oauth2.filterCallbackPath"));
        }

        @Override
        public void configure(WebSecurity web) throws Exception {
            web.ignoring().antMatchers(
                    "/", "/static/**", "/webjars/**");
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.exceptionHandling()
                        .authenticationEntryPoint(authenticationEntryPoint());
                http
                    .antMatcher("/auth/oauth/**")                       
                    .authorizeRequests()
                        .anyRequest().authenticated()
                .and()
                    .logout()
                        .logoutUrl("/logout")
                        .logoutSuccessUrl("/")                  
                .and()
                    .addFilterAfter(
                        oauth2ClientContextFilter,
                        ExceptionTranslationFilter.class)
                    .addFilterBefore(
                        oauth2ClientAuthenticationProcessingFilter(),
                        FilterSecurityInterceptor.class)
                    .anonymous()                        
                        .disable();
        }

        @Override
        protected AuthenticationManager authenticationManager() throws Exception {
            return new NoopAuthenticationManager();
        }

}

private static class NoopAuthenticationManager implements AuthenticationManager {
    @Override
    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {
        throw new UnsupportedOperationException(
                "No authentication should be done with this AuthenticationManager");
    }
}

@Bean           
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
}

While accessing the callback url api/auth/oauth/callback, I get following exception:

访问回调 url 时api/auth/oauth/callback,出现以下异常:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.oauth2ClientContext': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton

org.springframework.beans.factory.BeanCreationException:创建名为“scopedTarget.oauth2ClientContext”的 bean 时出错:当前线程的作用域“会话”未激活;如果您打算从单例引用它,请考虑为此 bean 定义一个作用域代理

On searching SO, the suggested solution is to add RequestContextListenerbean but even after adding that I got no success.

在搜索 SO 时,建议的解决方案是添加RequestContextListenerbean 但即使添加后我也没有成功。

One solutionalso suggested using FilterRegistrationBeanbut I am not using Springboot so I am not sure whether it would have solved my problem or not.

一种解决方案也建议使用,FilterRegistrationBean但我没有使用 Springboot,所以我不确定它是否能解决我的问题。

Full exception trace:

完整的异常跟踪:

2018-02-22 12:47:36,440 - /api/auth/oauth/callback org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.oauth2ClientContext': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request. at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:355) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:192) at com.sun.proxy.$Proxy64.getAccessToken(Unknown Source) at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:169) at org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:105) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:100) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) at org.eclipse.jetty.servlets.UserAgentFilter.doFilter(UserAgentFilter.java:83) at org.eclipse.jetty.servlets.GzipFilter.doFilter(GzipFilter.java:364) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585) at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:221) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515) at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97) at org.eclipse.jetty.server.Server.handle(Server.java:497) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310) at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257) at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635) at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555) at java.lang.Thread.run(Unknown Source) Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request. at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) at org.springframework.web.context.request.SessionScope.get(SessionScope.java:91) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340) ... 55 more

2018 年 2 月 22 日 12:47:36,440 - /api/auth/oauth/callback org.springframework.beans.factory.BeanCreationException:创建名为“scopedTarget.oauth2ClientContext”的 bean 时出错:当前范围“会话”未激活线; 如果您打算从单例中引用它,请考虑为此 bean 定义范围代理;嵌套异常是 java.lang.IllegalStateException: No thread-bound request found: 您是指实际 Web 请求之外的请求属性,还是在原始接收线程之外处理请求?如果您实际上是在 Web 请求中操作并且仍然收到此消息,则您的代码可能在 DispatcherServlet/DispatcherPortlet 之外运行:在这种情况下,使用 RequestContextListener 或 RequestContextFilter 来公开当前请求。在组织。您是指实际 Web 请求之外的请求属性,还是在原始接收线程之外处理请求?如果您实际上是在 Web 请求中操作并且仍然收到此消息,则您的代码可能在 DispatcherServlet/DispatcherPortlet 之外运行:在这种情况下,使用 RequestContextListener 或 RequestContextFilter 来公开当前请求。在 org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) 在 org.springframework.web.context.request.SessionScope.get(SessionScope.java:91) 在 org.springframework.beans.factory .support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340) ... 55 更多 或处理原始接收线程之外的请求?如果您实际上是在 Web 请求中操作并且仍然收到此消息,则您的代码可能在 DispatcherServlet/DispatcherPortlet 之外运行:在这种情况下,使用 RequestContextListener 或 RequestContextFilter 来公开当前请求。在 org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) 在 org.springframework.web.context.request.SessionScope.get(SessionScope.java:91) 在 org.springframework.beans.factory .support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340) ... 55 更多 或处理原始接收线程之外的请求?如果您实际上是在 Web 请求中操作并且仍然收到此消息,则您的代码可能在 DispatcherServlet/DispatcherPortlet 之外运行:在这种情况下,使用 RequestContextListener 或 RequestContextFilter 来公开当前请求。在 org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) 在 org.springframework.web.context.request.SessionScope.get(SessionScope.java:91) 在 org.springframework.beans.factory .support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340) ... 55 更多 使用 RequestContextListener 或 RequestContextFilter 来公开当前请求。在 org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) 在 org.springframework.web.context.request.SessionScope.get(SessionScope.java:91) 在 org.springframework.beans.factory .support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340) ... 55 更多 使用 RequestContextListener 或 RequestContextFilter 来公开当前请求。在 org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) 在 org.springframework.web.context.request.SessionScope.get(SessionScope.java:91) 在 org.springframework.beans.factory .support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340) ... 55 更多

回答by tryingToLearn

I solved the problem. And in this era of Springboot, someone who is working on a slightly older system, might find the answer useful, so sharing it.

我解决了这个问题。在这个时代Springboot,使用稍旧系统的人可能会发现答案有用,所以分享它。

The RequestContextListenerneeds to be added in jetty configuration like this:

RequestContextListener在这样的码头配置要添加的需求:

context.addEventListener(new RequestContextListener());

I was adding it in my security config file, like this:

我将它添加到我的安全配置文件中,如下所示:

@Bean
@Order(0)
public RequestContextListener requestContextListener() {
    return new RequestContextListener();
}

回答by S.Step

Someone can find this useful, add following in AbstractAnnotationConfigDispatcherServletInitializer implemntation class:

有人会发现这很有用,在 AbstractAnnotationConfigDispatcherServletInitializer 实现类中添加以下内容:

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    super.onStartup(servletContext);
    servletContext.addListener(new RequestContextListener());
}

回答by Felipe

@Bean
public OAuth2ClientContext oAuth2ClientContext() {
    return new DefaultOAuth2ClientContext();
}