如何基于HttpServletRequest配置Spring Boot Web安全,按请求头跳过JWT认证
基于HttpServletRequest配置Spring Boot Web安全,实现按请求头跳过JWT认证
你的需求是:当请求头包含sourceSystem且值为External时,跳过JWT认证;其他情况必须进行JWT认证。但当前的配置存在核心问题——configure(HttpSecurity)方法是在Spring容器启动时执行的,并非每次请求触发,所以直接在这里获取HttpServletRequest根本拿不到当前请求的头信息,逻辑完全不生效。
下面是两种可行的修正方案:
方案一:自定义RequestMatcher配置授权规则
通过自定义RequestMatcher来匹配需要跳过JWT的请求,在Spring Security的授权规则中直接配置放行。
1. 自定义RequestMatcher
public class SkipJwtRequestMatcher implements RequestMatcher { @Override public boolean matches(HttpServletRequest request) { // 读取请求头,判断是否符合跳过条件(忽略大小写可根据需求调整) String sourceSystem = request.getHeader("sourceSystem"); return "EXTERNAL".equalsIgnoreCase(sourceSystem); } }
2. 修改WebSecurityConfig配置
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; @Autowired private UserDetailsService jwtUserDetailsService; @Autowired private JwtRequestFilter jwtRequestFilter; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(HttpSecurity httpSecurity) throws Exception { // 实例化自定义匹配器 RequestMatcher skipJwtMatcher = new SkipJwtRequestMatcher(); httpSecurity.csrf().disable() .authorizeRequests() // 固定放行的路径 .antMatchers("/test").permitAll() // OPTIONS请求统一放行 .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 符合跳过条件的请求直接放行 .requestMatchers(skipJwtMatcher).permitAll() // 其余所有请求必须认证 .anyRequest().authenticated() .and() .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint) .and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); httpSecurity.cors(); } }
方案二:在JWT过滤器中直接判断跳过
修改JwtRequestFilter,在每次请求进入过滤器时先判断是否需要跳过认证,符合条件则直接放行,不执行JWT验证逻辑。
@Component public class JwtRequestFilter extends OncePerRequestFilter { // 注入你的JWT工具类、UserDetailsService等依赖 @Autowired private JwtTokenUtil jwtTokenUtil; @Autowired private UserDetailsService jwtUserDetailsService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { // 先判断是否需要跳过JWT认证 String sourceSystem = request.getHeader("sourceSystem"); if ("EXTERNAL".equalsIgnoreCase(sourceSystem)) { // 直接放行,不处理JWT验证 chain.doFilter(request, response); return; } // 原有JWT验证逻辑继续执行 String requestTokenHeader = request.getHeader("Authorization"); String username = null; String jwtToken = null; // JWT Token在Authorization头中,格式为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); if (jwtTokenUtil.validateToken(jwtToken, userDetails)) { UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); usernamePasswordAuthenticationToken .setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); } } chain.doFilter(request, response); } }
方案对比
- 方案一更贴合Spring Security的配置范式,将授权规则集中在配置类中管理,逻辑清晰。
- 方案二更灵活,适合需要在过滤器层做额外处理的场景,比如跳过认证时需要记录日志等操作。
内容的提问来源于stack exchange,提问作者user3744825
相关产品推荐
相关产品推荐

