添加Spring Security后,无法获取Apache AJP传递的RemoteUser问题
解决Spring Security引入后无法获取Apache通过AJP传递的RemoteUser问题
我之前处理过一模一样的场景——当你在Spring Boot项目中加入Spring Security依赖后,它会全盘接管应用的认证逻辑,默认不会自动识别Apache通过AJP协议传递过来的远程用户信息,这就是你调用request.getRemoteUser()返回null的核心原因。
下面是一步步的解决方案:
1. 确保Spring Boot的AJP配置正确
首先要保证你的Spring Boot应用已经开启AJP支持,并且信任Apache所在的代理服务器。在application.properties(或application.yml)中添加以下配置:
server.ajp.enabled=true # 替换成你的Apache服务器实际IP,允许该IP传递认证信息 server.ajp.trusted-proxies=127.0.0.1 server.ajp.protocol=AJP/1.3
2. 配置Spring Security接收预认证用户信息
Spring Security需要明确配置,让它信任Apache已经完成的认证,并提取Apache通过AJP传递的REMOTE_USER信息。创建一个Spring Security配置类:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; import org.springframework.security.core.userdetails.AuthenticationUserDetailsService; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider; import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .anyRequest().authenticated() ) // 添加预认证过滤器,优先处理Apache传递的用户信息 .addFilterBefore(requestHeaderAuthenticationFilter(), RequestHeaderAuthenticationFilter.class) .authenticationProvider(preAuthenticatedAuthenticationProvider()); // 如果你的场景不需要CSRF保护(比如内部系统SSO),可以关闭 http.csrf(csrf -> csrf.disable()); return http.build(); } @Bean public RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter() { RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter(); // 指定从哪个请求头/属性获取用户名,Apache通过AJP传递的默认是REMOTE_USER filter.setPrincipalRequestHeader("REMOTE_USER"); // 因为Apache已经完成认证,不需要凭证信息 filter.setCredentialsRequestHeader(null); filter.setAuthenticationManager(authentication -> authentication); return filter; } @Bean public PreAuthenticatedAuthenticationProvider preAuthenticatedAuthenticationProvider() { PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider(); // 配置用户详情服务,这里简单返回一个默认用户,你可以根据实际需求扩展(比如从数据库加载权限) provider.setPreAuthenticatedUserDetailsService(userDetailsService()); return provider; } @Bean public AuthenticationUserDetailsService userDetailsService() { return token -> new org.springframework.security.core.userdetails.User( token.getPrincipal().toString(), "", java.util.Collections.singletonList(new org.springframework.security.core.authority.SimpleGrantedAuthority("ROLE_USER")) ); } // 可选:放行静态资源(如果有需要) @Bean public WebSecurityCustomizer webSecurityCustomizer() { return web -> web.ignoring().requestMatchers("/static/**"); } }
3. 验证Apache的AJP配置
最后确认你的Apache配置中,已经正确将认证后的用户名通过AJP传递给Spring Boot。比如:
# AJP代理配置 ProxyPass / ajp://localhost:8009/ ProxyPassReverse / ajp://localhost:8009/ # 确保SSO认证后的用户名被放入REMOTE_USER头传递给后端 RequestHeader set REMOTE_USER %{REMOTE_USER}s
完成以上配置后,重新启动Spring Boot应用,再次访问/sso接口,request.getRemoteUser()就能正确获取到Apache传递的用户名了。
内容的提问来源于stack exchange,提问作者Kumar
相关产品推荐
相关产品推荐

