Spring Boot Security如何对携带特定请求头的请求禁用授权校验
实现方法
核心逻辑是在JWT资源服务器的校验过滤器执行前,识别到携带指定internal-key请求头的请求,直接给安全上下文注入可信认证身份,即可跳过后续JWT校验流程,不会被拦截。
方案1:自定义过滤器(推荐)
这种方式兼容性最好,不会打乱Security的过滤器链顺序,同时能给内部请求注入合法身份,适配业务代码里读取安全上下文的场景。
- 先写自定义内部请求校验过滤器,继承
OncePerRequestFilter保证单次请求只执行一次:
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Collections; public class InternalRequestFilter extends OncePerRequestFilter { // 密钥建议从配置文件注入,不要硬编码 private final String validInternalKey; public InternalRequestFilter(String validInternalKey) { this.validInternalKey = validInternalKey; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String requestKey = request.getHeader("internal-key"); // 头存在且值匹配时,注入内部可信身份 if (validInternalKey.equals(requestKey)) { UsernamePasswordAuthenticationToken internalAuth = new UsernamePasswordAuthenticationToken( "internalCaller", null, Collections.singletonList(new SimpleGrantedAuthority("ROLE_INTERNAL")) ); SecurityContextHolder.getContext().setAuthentication(internalAuth); } filterChain.doFilter(request, response); } }
- 修改原有安全配置,把自定义过滤器加到JWT校验过滤器
BearerTokenAuthenticationFilter之前:
import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter; import org.springframework.beans.factory.annotation.Value; @Configuration public class CustomSecurityConfiguration extends WebSecurityConfigurerAdapter { // 从配置文件读取内部密钥,示例配置项:security.internal-key=你的自定义复杂密钥 @Value("${security.internal-key}") private String internalKey; @Override protected void configure(HttpSecurity http) throws Exception { http .addFilterBefore(new InternalRequestFilter(internalKey), BearerTokenAuthenticationFilter.class) .authorizeRequests(authz -> authz .anyRequest().authenticated()) .oauth2ResourceServer(oauth2 -> oauth2.jwt()); } }
方案2:轻量规则配置(快速实现)
如果不需要在业务逻辑里获取内部请求的认证身份,可以直接在授权规则里加头匹配放行逻辑,注意规则顺序必须放在anyRequest之前,否则不会生效:
@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests(authz -> authz // 匹配携带internal-key头的请求直接放行 .requestMatchers(req -> req.getHeader("internal-key") != null).permitAll() .anyRequest().authenticated()) .oauth2ResourceServer(oauth2 -> oauth2.jwt()); }
注意事项:
- 不要使用过于简单的
internal-key值,生产环境请使用足够长度的随机密钥,定期轮换- 方案2的
permitAll不会给请求注入认证身份,如果业务代码依赖SecurityContextHolder获取登录用户信息,内部请求会出现空指针,优先选择方案1- 如果需要限制内部请求的权限范围,可以在注入认证身份时按需分配权限角色,在授权规则里做细粒度控制
内容的提问来源于stack exchange,提问作者Pavan Kumar Lekkala
相关产品推荐
相关产品推荐

