非Spring Boot环境下Spring Data Rest+Spring Security配置问题排查
你在搭建一个不依赖Spring Boot的Spring应用,集成了Spring Data Rest和Spring Security,虽然安全相关的Bean都成功创建了,但请求完全没经过安全过滤器链就直接进入了控制器方法。咱们来一步步拆解你的配置,找出问题所在:
核心问题:Security配置的上下文位置错误
Spring Security的过滤器链是注册在Servlet容器层面的,它依赖**根应用上下文(Root Application Context)**中的Bean来初始化。但你的配置里犯了一个关键错误:把SecurityConfig放到了DispatcherServlet的上下文里,而不是根上下文。
看你的代码:
AppInitializer的getRootConfigClasses()只返回了AppConfig.class,根上下文里没有Security相关配置WebConfig通过@Import导入了SecurityConfig,这导致Security的Bean只存在于DispatcherServlet的Web上下文里
这种情况下,Spring Security无法在Servlet容器中注册它的过滤器链,请求自然不会经过安全校验。
具体修复步骤
1. 把SecurityConfig移到根应用上下文
修改AppInitializer的getRootConfigClasses()方法,将SecurityConfig加入根配置类数组:
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { // 根上下文包含核心配置和安全配置 return new Class[]{AppConfig.class, SecurityConfig.class}; } @Override protected Class<?>[] getServletConfigClasses() { // Web上下文只负责MVC和Spring Data Rest相关配置 return new Class[]{WebConfig.class}; } // 其他方法保持不变... }
或者,你也可以在AppConfig中直接导入SecurityConfig,效果是一样的:
@Configuration @ComponentScan({"com.demo.gallery"}) @Import({MongoConfig.class, SecurityConfig.class}) public class AppConfig { // 原Bean方法保持不变... }
2. 移除WebConfig中对SecurityConfig的导入
既然已经把SecurityConfig放到根上下文了,WebConfig里的导入就不需要了,修改后:
@Configuration @Import({RepositoryRestMvcConfiguration.class}) public class WebConfig { // 原ResourceProcessor和RepositoryRestConfigurer Bean保持不变... }
3. 完善Security的HttpSecurity配置
你当前的configure(HttpSecurity)只是调用了super.configure(http),而父类的默认配置是允许所有请求的,这显然不符合安全需求。建议根据你的业务场景调整,比如:
@Override protected void configure(HttpSecurity http) throws Exception { // 禁用CSRF(如果是纯API服务可以考虑,前端页面的话建议保留) http.csrf().disable() // 配置请求权限规则 .authorizeRequests() .antMatchers("/api/**").authenticated() // 所有API接口需要认证 .anyRequest().permitAll() // 其他请求允许匿名访问 .and() .httpBasic(); // 启用HTTP Basic认证,也可以换成表单登录等方式 }
4. 确保Security过滤器被自动注册(可选)
在非Spring Boot环境下,Spring Security会通过AbstractSecurityWebApplicationInitializer自动注册过滤器链。如果上面的修改后还是有问题,可以手动创建这个类:
public class SecurityWebInitializer extends AbstractSecurityWebApplicationInitializer { // 不需要写任何代码,这个类会自动注册springSecurityFilterChain过滤器 }
这个类会自动在Servlet容器中注册DelegatingFilterProxy,绑定到Spring Security的过滤器链Bean上,确保所有请求都经过安全校验。
总结一下
问题的核心就是Security配置的上下文位置不对,导致过滤器链无法被Servlet容器加载。把SecurityConfig移到根应用上下文,再完善一下权限配置,就能让请求正常经过安全过滤器链了。
内容的提问来源于stack exchange,提问作者slesh

