Spring Boot所有请求重定向至/authenticate端点问题求助
问题描述
Spring Boot应用中,标注@RestController的JwtAuthenticationController类包含/authenticate和/register两个POST端点,但访问任意端点(包括/register)都会被重定向至/authenticate。已确认端点映射为POST方法,重启应用、检查URL、验证参数类及业务方法均无效,日志无错误信息。
控制器简化代码
@RestController @CrossOrigin public class JwtAuthenticationController { // Autowired字段及其他方法已省略 @PostMapping(value = "/authenticate") public ResponseEntity<?> createAuthenticationToken(@RequestBody JwtRequest authenticationRequest) throws Exception { // 认证逻辑已省略 } @PostMapping(value = "/register") public ResponseEntity<?> saveUser(@RequestBody UserRq user) throws Exception { // 用户注册逻辑已省略 } }
相关参考代码
JwtRequestFilter代码
public class JwtRequestFilter extends OncePerRequestFilter { private final JwtTokenUtil jwtTokenUtil; private final JwtUserDetailsService jwtUserDetailsService; public JwtRequestFilter(JwtTokenUtil jwtTokenUtil, JwtUserDetailsService jwtUserDetailsService) { this.jwtTokenUtil = jwtTokenUtil; this.jwtUserDetailsService = jwtUserDetailsService; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { final String requestTokenHeader = request.getHeader("Authorization"); String username = null; String jwtToken = null; // JWT Token格式为"Bearer token",移除Bearer前缀获取Token if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) { jwtToken = requestTokenHeader.substring(7); try { username = jwtTokenUtil.getUsernameFromToken(jwtToken); } catch (IllegalArgumentException e) { System.out.println("Unable to get JWT Token"); } catch (ExpiredJwtException e) { System.out.println("JWT Token has expired"); } } else { logger.warn("JWT Token does not begin with Bearer String"); } // 获取Token后进行验证 if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username); // 若Token有效,配置Spring Security手动设置认证 if (jwtTokenUtil.validateToken(jwtToken, userDetails)) { UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); usernamePasswordAuthenticationToken .setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); // 在上下文设置认证后,当前用户即被认证,可通过Spring Security配置 SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); } } chain.doFilter(request, response); }
SecurityConfiguration代码
package jb.microservices.login.util; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpStatus; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; import org.springframework.security.web.authentication.HttpStatusEntryPoint; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.OrRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; @Autowired private UserDetailsService jwtUserDetailsService; @Autowired private JwtRequestFilter jwtRequestFilter; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { // 配置AuthenticationManager,使其知道从何处加载用户凭证 // 使用BCryptPasswordEncoder auth.userDetailsService(jwtUserDetailsService).passwordEncoder(new BCryptPasswordEncoder()); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override public void configure(WebSecurity web) { web.ignoring().antMatchers("/authenticate", "/register"); } @Override protected void configure(HttpSecurity httpSecurity) throws Exception { // 本示例无需CSRF httpSecurity.csrf().disable() // 不对该请求进行认证 .authorizeRequests().antMatchers("/authenticate", "/register").permitAll(). // 所有其他请求需认证 anyRequest().authenticated().and(). // 使用无状态会话,不存储用户状态 exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 添加过滤器,在每个请求中验证Token httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); } }
排查与解决思路
1. 修复安全配置规则冲突
当前同时在WebSecurity和HttpSecurity中配置了对/authenticate、/register的放行规则,两者作用不同:
WebSecurity.ignoring()会让请求完全绕过Spring Security过滤器链HttpSecurity.permitAll()允许请求通过过滤器链但无需认证
重复配置可能导致路由异常,建议保留HttpSecurity的规则,修改WebSecurity配置为仅忽略静态资源:
@Override public void configure(WebSecurity web) { web.ignoring().antMatchers("/css/**", "/js/**", "/images/**"); }
2. 检查请求重定向状态
使用Postman或浏览器开发者工具查看请求响应状态码:
- 若出现301/302,需确认请求URL是否带多余斜杠(如
/register/),或请求方法是否为POST(而非GET)
3. 校验认证入口点实现
检查JwtAuthenticationEntryPoint的commence方法,确保仅返回401错误而非重定向:
@Component public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); } }
4. 开启请求映射日志排查
在application.properties中添加配置,查看请求实际映射的控制器方法:
logging.level.org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping=DEBUG
启动应用后访问/register,日志会明确显示请求被路由到哪个方法,定位是否为路由配置问题。
5. 排查过滤器干扰
暂时移除JwtRequestFilter,测试/register是否能正常访问,逐步排除其他自定义过滤器或拦截器的干扰。
内容的提问来源于stack exchange,提问作者Joanmi
相关产品推荐
相关产品推荐

