Spring在AuthenticationSuccessHandler中自动装配会话范围bean是不起作用的

时间:2016-11-02 12:49:47

标签: java spring session spring-security

我正在使用spring security,我想在用户成功登录后在会话中初始化一个对象User

安全配置如下:

@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/**");
    }

}

User

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

    private String selectedSystem;
    private String selectedBank;

}

SimpleUrlAuthenticationSuccessHandler如下:

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

    @Autowired
    private User user;

错误是:

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)

我已将RequestContextListener添加到Web应用程序,如下所示:

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, "/*");

    }

}

我已阅读How to retrieve a session-scoped bean inside AuthenticationSuccessHandler?,但它没有帮助

当我尝试Autowire没有会话bean时,它运行正常。

知道如何修复它吗?!

1 个答案:

答案 0 :(得分:1)

您的例外是关于您为其提供会话范围的用户bean。您似乎错过了会话​​范围的某些配置。

在Spring MVC中,我们有额外的范围,因为我们正在使用Web应用程序上下文,其他范围是:会话范围,请求范围,应用程序范围。

我通常使用XML配置,所以我的答案将是那种格式,之后你可以翻译成java配置。

在web.xml中,你需要添加一个监听器,如:

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

此侦听器将与每个请求相关联。

现在,使用您希望拥有会话范围的bean,您需要添加一个范围代理,为此,您需要将aop命名空间添加到您的配置中文件,和:

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

此bean应位于dispatcher-servlet.xml文件

这就是你,你已经全部准备好了。

在此处查看如何在Java配置中使用scoped-proxy:

Spring JavaConfig of aop:scoped proxy