先说几个核心判断:基于Spring Security实现API Key认证,本质上就是自定义一套过滤器、令牌和认证提供者,让原本面向用户名密码的认证流程能够无缝适配接口密钥模式。整个方案由四个关键组件构成,下面逐一拆解。
核心实现类
ApiKeyAuthFilter认证过滤器ApiKeyAuthenticationToken认证令牌ApiKeyAuthenticationProviderAPI认证鉴权SecurityConfig安全配置类
ApiKeyAuthFilter 认证过滤器
方法概要

OncePerRequestFilter 这个抽象基类,由 Spring Web 专门提供,用于确保过滤器在一次HTTP请求的完整处理流程中仅执行一次。继承它,你只需要实现 doFilterInternal 方法即可。
通过 @Component 注解标注,自动注册为 Spring Bean。然后注入 AuthenticationManager——这是 Spring Security 的认证总入口。调用它的 authenticate() 方法,会遍历所有 AuthenticationProvider,找到支持 ApiKeyAuthenticationToken 的那个(即你自定义的 ApiKeyAuthenticationProvider),执行验证逻辑。
@Component
public class ApiKeyAuthFilter extends OncePerRequestFilter {
@Autowired
private AuthenticationManager authenticationManager; // 注入 AuthenticationManager
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String apiKey = request.getHeader("X-API-Key");
// 只处理 /api/ 开头的接口(根据你的需求调整)
if (apiKey != null && request.getRequestURI().startsWith("/api/")) {
try {
// 1. 创建未认证的 Token
ApiKeyAuthenticationToken authToken = new ApiKeyAuthenticationToken(apiKey);
// 2. ⭐️ 关键:显式调用 AuthenticationManager 进行认证
Authentication authenticated = authenticationManager.authenticate(authToken);
// 3. 将认证成功的 Token 放入 SecurityContext
SecurityContextHolder.getContext().setAuthentication(authenticated);
} catch (AuthenticationException e) {
// 认证失败:清空上下文,并返回 401
SecurityContextHolder.clearContext();
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("Invalid API Key");
return;
}
}
filterChain.doFilter(request, response);
}
}
ApiKeyAuthenticationToken 认证令牌
AbstractAuthenticationToken 是 Spring Security 提供的认证令牌抽象类。继承它后,只需实现用户登录及令牌校验的操作。当 setAuthenticated 为 true 时,直接放行。
public class ApiKeyAuthenticationToken extends AbstractAuthenticationToken {
private final Object principal;
public ApiKeyAuthenticationToken(Object principal) {
// credentials 设为 null(API Key 已用于认证,无需再存)
super(null);
this.principal = principal;
// 初始为未认证(由 AuthenticationProvider 设置为 true)
setAuthenticated(false);
}
@Override
public Object getCredentials() {
return principal;
}
@Override
public Object getPrincipal() {
return principal;
}
}
ApiKeyAuthenticationProvider 认证提供者
这是 Spring Security 中实现 API Key 认证的核心组件,负责验证客户端传入的 API Key 是否合法,并生成已认证的安全上下文(Authentication)。
核心关系:接口约定 + 方法实现(契约模式)
AuthenticationProvider 是 Spring Security 定义的认证核心接口(契约),authenticate() 是这个接口强制要求实现的核心方法(契约内容)。简单说:
implements AuthenticationProvider:表示你的类“承诺遵守 Spring Security 的认证规则”;authenticate():是你兑现这个承诺的“具体认证逻辑”(校验 API Key、用户名密码等)。
@Component
public class ApiKeyAuthenticationProvider implements AuthenticationProvider {
@Autowired
private ISysApiKeysService sysApiKeysService;
// 核心方法:执行具体的认证逻辑
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String providedKey = (String) authentication.getCredentials();
SysApiKeys sysApiKeys = sysApiKeysService.selectByApikey(providedKey);
if (sysApiKeys != null) {
ApiKeyAuthenticationToken authenticatedToken =
new ApiKeyAuthenticationToken(sysApiKeys);
return authenticatedToken;
}
throw new BadCredentialsException("Invalid API Key");
}
// 辅助方法:判断当前 Provider 是否支持处理某个类型的 Token
@Override
public boolean supports(Class> authentication) {
return ApiKeyAuthenticationToken.class.isAssignableFrom(authentication);
}
}
SecurityConfig 安全配置类
@EnableMethodSecurity 注解(配合 @Configuration)用于启用方法级别的权限控制,例如通过 @PreAuthorize、@Secured 等注解限制接口访问。
addFilterBefore() 是 Spring Security 中用于自定义过滤器链顺序的核心方法,其作用是在指定的内置(或已注册)Filter 之前插入你自己的 Filter。因此必须在原有 UsernamePasswordAuthenticationFilter 认证之前先执行 apiKeyAuthFilter。
// 添加 Api filter .addFilterBefore(apiKeyAuthFilter, UsernamePasswordAuthenticationFilter.class)
protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception 是 Spring Security 中配置 HTTP 层面安全规则的核心方法。它的核心作用是通过 HttpSecurity 对象定制请求的安全策略——哪些请求需要认证、哪些放行、用什么方式认证、异常如何处理等。下面从核心作用、常用配置、实战示例、与方法级权限的区别四个维度来讲清楚。
- 该方法的本质是构建一个
SecurityFilterChain过滤器链,Spring Security 会将其应用到所有 HTTP 请求上,实现:
控制哪些请求需要认证、哪些请求可以匿名访问(放行);
定义认证方式(如 HTTP Basic、表单登录、JWT 过滤器等);
配置跨域(CORS)、CSRF 防护、会话管理;
定制认证失败、权限不足的响应(如返回 JSON 而非默认页面);
整合自定义过滤器(如 JWT 校验过滤器)。
完整代码
/**
* spring security配置
*
* @author
*/
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Configuration
public class SecurityConfig
{
/**
* 自定义用户认证逻辑
*/
@Autowired
private UserDetailsService userDetailsService;
/**
* 认证失败处理类
*/
@Autowired
private AuthenticationEntryPointImpl unauthorizedHandler;
/**
* 退出处理类
*/
@Autowired
private LogoutSuccessHandlerImpl logoutSuccessHandler;
/**
* token认证过滤器
*/
@Autowired
private JwtAuthenticationTokenFilter authenticationTokenFilter;
@Autowired
private ApiKeyAuthFilter apiKeyAuthFilter;
/**
* 跨域过滤器
*/
@Autowired
private CorsFilter corsFilter;
/**
* 允许匿名访问的地址
*/
@Autowired
private PermitAllUrlProperties permitAllUrl;
@Autowired
ApiKeyAuthenticationProvider apiKeyAuthenticationProvider;
/**
* 身份验证实现
*/
@Bean
public AuthenticationManager authenticationManager()
{
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(userDetailsService);
daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder());
return new ProviderManager(Arrays.asList(daoAuthenticationProvider,
apiKeyAuthenticationProvider));
}
/**
* anyRequest | 匹配所有请求路径
* access | SpringEl表达式结果为true时可以访问
* anonymous | 匿名可以访问
* denyAll | 用户不能访问
* fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录)
* hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问
* hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问
* hasAuthority | 如果有参数,参数表示权限,则其权限可以访问
* hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
* hasRole | 如果有参数,参数表示角色,则其角色可以访问
* permitAll | 用户可以任意访问
* rememberMe | 允许通过remember-me登录的用户访问
* authenticated | 用户登录后可访问
*/
@Bean
protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception
{
return httpSecurity
// CSRF禁用,因为不使用session
.csrf(csrf -> csrf.disable())
// 禁用HTTP响应标头
.headers((headersCustomizer) -> {
headersCustomizer.cacheControl(cache -> cache.disable()).frameOptions(options -> options.sameOrigin());
})
// 认证失败处理类
.exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
// 基于token,所以不需要session
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// 注解标记允许匿名访问的url
.authorizeHttpRequests((requests) -> {
permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
requests.antMatchers("/login", "/register", "/captchaImage").permitAll()
// 静态资源,可匿名访问
.antMatchers(HttpMethod.GET,
"/",
"/*.html",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/profile/**",
"/cadre/neo4j/**",
"/cadre/evaluation/rqcode/**")
.permitAll()
.antMatchers(HttpMethod.POST,
"/cadre/cadre/home/recalculate")
.permitAll()
.antMatchers(
"/swagger-ui.html",
"/swagger-resources/**",
"/webjars/**",
"/*/api-docs",
"/cadre/evaluation/qrcode/**",
"/cadre/evaluation/grade/rqcodeScore/**",
"/druid/**")
.permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated();
})
// 添加Logout filter
.logout(logout -> logout.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler))
// 添加 Api filter
.addFilterBefore(apiKeyAuthFilter, UsernamePasswordAuthenticationFilter.class)
// 添加JWT filter
.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
// 添加CORS filter
.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class)
.addFilterBefore(corsFilter, LogoutFilter.class)
.build();
}
/**
* 强散列哈希加密实现
*/
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder()
{
return new BCryptPasswordEncoder();
}
}
以上就是基于Spring Security实现API Key认证的完整方案。
