java - Spring 在 AuthenticationSuccessHandler 中 Autowiring session 范围 bean 不起作用

标签 java spring session spring-security

我正在使用 spring security,我想在用户成功登录后在 session 中初始化一个对象 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/**");
    }

}

用户

@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 添加到网络应用程序,如下所示:

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 无 session bean 时,它工作正常。

知道如何解决吗?!

最佳答案

你的异常是关于你的用户 bean,你给了它一个 session 范围。您似乎错过了 session ​​范围的一些配置。

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

我通常使用 XML 配置,所以我的回答将是那种格式,您可以在之后将其转换为 java 配置。

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

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

这个监听器将与每个进来的请求相关联。

现在,对于您希望具有 session 作用域的 bean,您需要向其添加一个作用域代理,为此您需要将 aop 命名空间添加到您的配置文件中,并且:

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

这个 bean 应该在 dispatcher-servlet.xml 文件中

到此为止,一切就绪。

在这里查看如何使用 scoped-proxy 和 java 配置:

Spring JavaConfig of aop:scoped proxy

关于java - Spring 在 AuthenticationSuccessHandler 中 Autowiring session 范围 bean 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40380387/

相关文章:

java - JHipster 按实体字段搜索实体

javascript - 单击浏览器的后退按钮时如何销毁 session

java - 使用 Jackson 进行反序列化 : "org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of [projectname]."

java - MyBatis SqlSession autoCommit = false 与 ExecutorType.BATCH

java - Android 设备在第一次 Activity 后挂起

java - Spring Boot - REST 方法返回接口(interface)

asp.net - 如何使用 AJAX 从服务器获取信息而不重置 session 超时?

c# - 检查 session 是否为空

java - 在 Servlet 类中创建方法是一种不好的做法吗?

java - MX Player 打开而不是通过 Intent 播放视频