Spring在AuthenticationSuccessHandler中自动装配会话范围bean不起作用
Posted
技术标签:
【中文标题】Spring在AuthenticationSuccessHandler中自动装配会话范围bean不起作用【英文标题】:Spring autowireing a session scope bean in AuthenticationSuccessHandler is not working 【发布时间】:2017-03-15 18:59:42 【问题描述】:我正在使用 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
none 会话 bean 时,它工作正常。
知道如何解决吗?!
【问题讨论】:
【参考方案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
【讨论】:
在服务器启动期间我遇到这个错误 名为“用户”的 Bean 应该是 [user.package.User] 类型,但实际上是 [com.sun.proxy.$Proxy36 ] 我不是说你真的使用了user.package.User,你需要使用你的包来代替。如果您的 User 类在 bla.bla.foo 的包中,则使用 bla.bla.foo.User 我当然用过我的包。看来错误是因为为User
bean设置了代理模式
那么,有什么问题?
亲爱的@Moshe 我已经在上面的答案中发送了错误。 .. 弹簧无法初始化。让我发送完整的错误行... 创建名称为“simpleUrlAuthenticationSuccessHandler”的 bean 时出错:通过字段“用户”表达的不满足依赖关系:名为“用户”的 Bean 应为 [foo.bar.User] 类型,但实际上是 [com.sun.proxy.$Proxy36] 类型;嵌套异常是 org.springframework.beans.factory.BeanNotOfRequiredTypeException:名为 'user' 的 Bean 应该是 [foo.bar.User] 类型,但实际上是 [com.sun.proxy.$Proxy36] 类型 以上是关于Spring在AuthenticationSuccessHandler中自动装配会话范围bean不起作用的主要内容,如果未能解决你的问题,请参考以下文章
Spring 4 安全、MySQL、c3p0 连接。登录在 Spring 5 中有效,但在 Spring 4 中无效
Spring源码学习:第1步--在Spring源码中添加最简单的Demo代码
避免在单个 jar 中合并多个 spring 依赖项时覆盖 spring.handlers/spring.schemas 的想法