如何在Spring Boot中用Spring Security实现Bearer头硬编码校验?
问题描述
我想对服务器做认证,不需要处理登录等逻辑,只验证请求头里的Authorization字段的Bearer Token,和硬编码的值对比,匹配就放行,不匹配就拒绝。我写了两个过滤器,但试了很多次还是返回401未授权错误。我看过连接数据库验证用户的文章,但只想通过过滤器校验请求头Token。
编辑1:
现在我知道Spring Security有15个过滤器,怎么确保系统只校验自定义请求头,忽略其他校验逻辑?
现有代码
SecurityConfig.java
package com.company.framework.filter; import javax.servlet.http.HttpServletResponse; 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.WebSecurityConfigurerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfig{ @Autowired private AuthFilter filtet; public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { System.out.println("reaching here3 "); http .csrf().disable() .authorizeRequests() .antMatchers("/api/v1/open/**").permitAll() .and() .exceptionHandling() .authenticationEntryPoint( (request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error here") ) .and() .sessionManagement() .and() .httpBasic().disable(); http .addFilter(filtet); return http.build(); } }
AuthFilter.java
package com.company.framework.filter; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; @Component public class AuthFilter extends OncePerRequestFilter{ @Override protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException { String authHeader = request.getHeader("Authorization"); System.out.println("here "); System.out.println(authHeader+"1"); if (authHeader != null && authHeader.length() == 0 && authHeader.startsWith("Bearer ")) { String jwt = authHeader.substring(7); System.out.println(authHeader+"2"); if (jwt == null) { response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid JWT Token in Bearer Header"); } else { String rev = "bfrek"; if (jwt.equals(rev)) { response.setStatus(200); } else { response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid JWT Token"); } } } filterChain.doFilter(request, response); } }
问题分析与修复方案
核心问题
- AuthFilter逻辑错误:条件
authHeader != null && authHeader.length() == 0 && authHeader.startsWith("Bearer ")矛盾,length() == 0会直接跳过有效Token的校验;且验证通过后仅设置200状态,未告知Spring Security已完成认证,后续过滤器仍会拦截请求。 - SecurityConfig配置缺失:未声明非开放接口需要认证,也未禁用不必要的会话机制,自定义过滤器的位置也未正确插入Spring Security链中。
修复后代码
1. 修正AuthFilter.java
package com.company.framework.filter; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; @Component public class AuthFilter extends OncePerRequestFilter { // 硬编码的有效Token private static final String VALID_TOKEN = "bfrek"; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 跳过开放接口的校验 if (request.getRequestURI().startsWith("/api/v1/open/")) { filterChain.doFilter(request, response); return; } String authHeader = request.getHeader("Authorization"); // 校验请求头格式 if (authHeader == null || !authHeader.startsWith("Bearer ")) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "缺少有效的Bearer Token"); return; } String token = authHeader.substring(7).trim(); // 对比Token值 if (!VALID_TOKEN.equals(token)) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "无效的Token"); return; } // 验证通过,向Spring Security上下文注入认证信息 Authentication authentication = new UsernamePasswordAuthenticationToken("system", null, null); SecurityContextHolder.getContext().setAuthentication(authentication); // 放行请求 filterChain.doFilter(request, response); } }
2. 修正SecurityConfig.java
package com.company.framework.filter; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; 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.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @EnableWebSecurity public class SecurityConfig { @Autowired private AuthFilter authFilter; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // 禁用CSRF(无状态接口无需) .csrf().disable() // 授权规则:开放接口允许所有人,其余需认证 .authorizeRequests() .antMatchers("/api/v1/open/**").permitAll() .anyRequest().authenticated() .and() // 禁用HTTP Basic认证 .httpBasic().disable() // 设置无状态会话,不维护会话信息 .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() // 自定义未授权响应 .exceptionHandling() .authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "未授权访问") ); // 将自定义过滤器插入到Spring Security认证过滤器之前 http.addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); } }
关键修复点
- 修正Token校验逻辑:去掉矛盾的长度判断,先校验请求头格式再对比Token值。
- 注入认证上下文:验证通过后向
SecurityContextHolder设置认证信息,告知Spring Security请求已授权。 - 简化并完善Security配置:
- 明确非开放接口的认证要求;
- 设置无状态会话,禁用不必要的会话机制;
- 将自定义过滤器插入到Spring Security默认认证过滤器之前,确保优先执行;
- 清理冗余配置,减少不必要的过滤器执行。
内容的提问来源于stack exchange,提问作者Anubhav Sinha
相关产品推荐
相关产品推荐

