创建名为' scopedTarget.oauth2ClientContext'的bean时出错尽管定义了RequestContextListener

时间:2018-02-22 07:36:44

标签: java spring spring-security spring-security-oauth2

我的应用有多种弹簧安全配置,其中一种恰好是Oauth2(使用this eaxmple)。

一般来说,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看起来像这样:

@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();
}

访问回调网址api/auth/oauth/callback时,我遇到以下异常:

  

org.springframework.beans.factory.BeanCreationException:错误   使用name' scopedTarget.oauth2ClientContext':Scope创建bean   '会议'当前线程不活动;考虑定义一个   如果你打算从a引用它,那么这个bean的scoped代理   单

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

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

完整异常跟踪:

  

2018-02-22 12:47:36,440 - / api / auth / oauth / callback   org.springframework.beans.factory.BeanCreationException:错误   使用name' scopedTarget.oauth2ClientContext':Scope创建bean   '会议'当前线程不活动;考虑定义一个   如果你打算从a引用它,那么这个bean的scoped代理   单;嵌套异常是java.lang.IllegalStateException:否   发现线程绑定请求:您是指请求属性   在实际的Web请求之外,或处理外部的请求   原来收到的帖子?如果你实际在里面经营   一个Web请求仍然收到此消息,您的代码可能是   在DispatcherServlet / DispatcherPortlet之外运行:在这种情况下,   使用RequestContextListener或RequestContextFilter来公开   当前的要求。在   org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:355)     在   org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)     在   org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35)     在   org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:192)     在com.sun.proxy。$ Proxy64.getAccessToken(未知来源)at   org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:169)     在   org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:105)     在   org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)     在   org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331)     在   org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60)     在   org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331)     在   org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)     在   org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331)     在   org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)     在   org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331)     在   org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)     在   org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331)     在   org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)     在   org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331)     在   org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)     在   org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331)     在   org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:100)     在   org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)     在   org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331)     在   org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)     在   org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)     在   org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331)     在   org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)     在   org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331)     在   org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)     在   org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)     在   org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331)     在   org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)     在   org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)     在   org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347)     在   org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263)     在   org.eclipse.jetty.servlet.ServletHandler $ CachedChain.doFilter(ServletHandler.java:1652)     在   org.eclipse.jetty.servlets.UserAgentFilter.doFilter(UserAgentFilter.java:83)     在   org.eclipse.jetty.servlets.GzipFilter.doFilter(GzipFilter.java:364)     在   org.eclipse.jetty.servlet.ServletHandler $ CachedChain.doFilter(ServletHandler.java:1652)     在   org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)     在   org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:221)     在   org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)     在   org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)     在   org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)     在   org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)     在   org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)     在   org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215)     在   org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)     在org.eclipse.jetty.server.Server.handle(Server.java:497)处   org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310)at at   org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)     在   org.eclipse.jetty.io.AbstractConnection $ 2.run(AbstractConnection.java:540)     在   org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)     在   org.eclipse.jetty.util.thread.QueuedThreadPool $ 3.run(QueuedThreadPool.java:555)     在java.lang.Thread.run(未知来源)引起:   java.lang.IllegalStateException:找不到线程绑定请求:是   您指的是实际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个

3 个答案:

答案 0 :(得分:5)

我解决了这个问题。在SELECT * FROM schueler WHERE Geburtsdatum BETWEEN ALIKE "%2002" AND ALIKE "%2003"; 的这个时代,正在研究稍微旧一点的系统的人可能会觉得答案很有用,所以分享它。

需要在Jetty配置中添加Springboot,如下所示:

RequestContextListener

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

context.addEventListener(new RequestContextListener());

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

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