简体   繁体   中英

Spring autowireing a session scope bean in AuthenticationSuccessHandler is not working

I am using spring security and I want to initial an object User in session after user success login.

The security configuration is as below:

@Configuration
@EnableWebSecurity
@PropertySource("classpath://configs.properties")
public class SecurityContextConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private Environment env;

    @Autowired
    SimpleUrlAuthenticationSuccessHandler simpleUrlAuthenticationSuccessHandler;


    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {

        auth.inMemoryAuthentication()
            .withUser(env.getProperty("security.user1.userid"))
            .password(env.getProperty("security.user1.pass"))
            .roles(env.getProperty("security.user1.role"));
    }


    @Override   
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests().antMatchers("/*.cm")
                .access("hasRole('ADMIN')")
                .and()
                .formLogin()
                    .loginPage("/public-page.cm")
                    .loginProcessingUrl("/j_spring_security_check")
                    .usernameParameter("j_username")
                    .passwordParameter("j_password")
                    .successHandler(simpleUrlAuthenticationSuccessHandler)
                    .failureUrl("/public-page-authentication-failure.cm")
                .and()
                    .logout()
                    .logoutSuccessUrl("/public-page.cm")
                    .invalidateHttpSession(true)
                    .logoutUrl("/j_spring_security_logout")
                .and()
                    .csrf().disable();

    }

    /**
     * configure which patterns the spring security should not be applied
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/index.jsp", "/public-page.jsp", "/public-page.cm",
                "/public-page-authentication-failure.cm", "/images/**", "/css/**", "/js/**");
    }

}

The User is

@Component
@Scope("session")
public class User {

    private String selectedSystem;
    private String selectedBank;

}

The SimpleUrlAuthenticationSuccessHandler is as:

@Component
public class SimpleUrlAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    protected Log logger = LogFactory.getLog(this.getClass());

    @Autowired
    private User user;

The error is:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'user': 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:202)

I have added the RequestContextListener to web app as below:

public class WebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
        appContext.register(DatabaseContextConfig.class);


        servletContext.addListener(new ContextLoaderListener(appContext));
        servletContext.addListener(new RequestContextListener());

        //Add Spring security filter
        FilterRegistration.Dynamic springSecurityFilterChain = servletContext.addFilter(
                AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME,  DelegatingFilterProxy.class);
        springSecurityFilterChain.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");

    }

}

I have read How to retrieve a session-scoped bean inside AuthenticationSuccessHandler? but it doesn't help

When I try to Autowire none session bean, it works fine.

Any idea how to fix it ?!

Your exception is about your user bean which you gave it a scope of session. It seems that you missed some configuration for the session scope.

In spring MVC we have additional scopes because we're working with a web application context, the additional scopes are: session scope, request scope, application scope.

I usally use XML configuration, so my answer will be in that format, you can do the translations to java configurations afterwards.

In the web.xml you'll need to add a listener, like that:

<listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

This listener will be associated with each request comes in.

Now, with your bean which you want to have a session scope, you'll need to add to it a scoped proxy, in order to do that you'll need to add the aop namespace to your configuration file, and:

<bean class="user.package.User" scope="session">
    <aop:scoped-proxy/>
</bean>

this bean should be on the dispatcher-servlet.xml file

That it, you're all set.

Look in here on how to use scoped-proxy with java configuration:

Spring JavaConfig of aop:scoped proxy

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM