Spring OAuth2资源服务器特定端点自定义令牌校验实现方法
实现基于固定令牌的端点自定义校验
现有配置背景
当前Spring OAuth2资源服务器通过Issuer URI验证JWT,核心配置如下:
@EnableWebSecurity class WebSecurityConfiguration { @Bean fun filterChain(http: HttpSecurity): SecurityFilterChain { http.authorizeRequests() .antMatchers("/actuator/health").permitAll() .antMatchers("/**").hasAnyRole("User", "Client") .anyRequest().authenticated() .and() .oauth2ResourceServer() .jwt() .jwtAuthenticationConverter(jwtAuthenticationConverter()) return http.build() } private fun jwtAuthenticationConverter(): Converter<Jwt?, out AbstractAuthenticationToken?> { val jwtConverter = JwtAuthenticationConverter() jwtConverter.setJwtGrantedAuthoritiesConverter(KeycloakRealmRoleConverter()) return jwtConverter } }
需求
为/api/custom/players端点实现基于环境变量PLAYERS_TOKEN的自定义令牌校验:请求需携带Bearer {PLAYERS_TOKEN}格式的Authorization头,校验通过后方可访问。
实现步骤
1. 读取环境变量
在配置类中注入环境变量PLAYERS_TOKEN:
@Value("\${PLAYERS_TOKEN}") private lateinit var playersToken: String
2. 实现自定义令牌校验过滤器
创建PlayerTokenFilter,继承OncePerRequestFilter,针对目标端点做令牌校验:
class PlayerTokenFilter( private val playersToken: String ) : OncePerRequestFilter() { override fun doFilterInternal( request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain ) { // 仅处理目标端点 if (request.requestURI.startsWith("/api/custom/players")) { val authHeader = request.getHeader("Authorization") // 校验Authorization头格式及令牌匹配 if (authHeader == null || !authHeader.startsWith("Bearer ")) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "缺失或无效的Authorization请求头") return } val token = authHeader.substring(7).trim() if (token != playersToken) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "无效令牌") return } // 校验通过,设置认证信息到SecurityContext val authentication = UsernamePasswordAuthenticationToken( "player-client", null, listOf(SimpleGrantedAuthority("ROLE_PLAYER")) ) SecurityContextHolder.getContext().authentication = authentication } // 继续执行后续过滤器链 filterChain.doFilter(request, response) } }
3. 配置SecurityFilterChain,整合自定义过滤器
修改原filterChain方法,为目标端点单独配置,添加自定义过滤器并设置对应权限:
@Bean fun filterChain(http: HttpSecurity): SecurityFilterChain { http .authorizeRequests() .antMatchers("/actuator/health").permitAll() // 目标端点需持有PLAYER角色(由自定义过滤器注入) .antMatchers("/api/custom/players/**").hasRole("PLAYER") .antMatchers("/**").hasAnyRole("User", "Client") .anyRequest().authenticated() .and() // 在用户名密码认证过滤器前执行自定义令牌校验 .addFilterBefore(PlayerTokenFilter(playersToken), UsernamePasswordAuthenticationFilter::class.java) .oauth2ResourceServer() .jwt() .jwtAuthenticationConverter(jwtAuthenticationConverter()) return http.build() }
补充说明
- 过滤器中注入的
ROLE_PLAYER是为了配合hasRole("PLAYER")的权限校验,确保只有通过令牌校验的请求能访问目标端点;若无需权限细分,也可将目标端点配置为permitAll(),但建议保留角色校验以维持权限体系一致性。 - 环境变量
PLAYERS_TOKEN需在部署时正确配置,禁止硬编码到代码中。
内容的提问来源于stack exchange,提问作者Hodl
相关产品推荐
相关产品推荐

