在 Spring 启动时忽略特定 Url 的 Bearer Token 验证
Ignore Bearer Token Validation for specific Urls in Spring Boot
我正在将微服务配置为资源服务器,它使用 JWK 端点来验证 JWT 令牌的签名。
我已将配置设置为允许服务中的所有 GET
请求。所有其他请求都根据范围和角色进行保护。这是我正在使用的配置。
@EnableReactiveMethodSecurity
class SecurityConfig : WebFluxConfigurer {
@Bean
fun authenticationEntryPoint(): ServerAuthenticationEntryPoint {
return JwtBearerTokenServerAuthenticationEntryPoint()
}
@Bean
fun accessDeniedHandler(): ServerAccessDeniedHandler {
return JwtTokenAccessDeniedHandler()
}
@Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
http
.authorizeExchange()
.pathMatchers(HttpMethod.GET).permitAll()
.pathMatchers("/docs/**", "/v2/api-docs/**", "/").permitAll()
// Client should have the required scope to write to products
.pathMatchers(HttpMethod.POST).hasAuthority(PRODUCT_WRITE_SCOPE)
.pathMatchers(HttpMethod.PUT).hasAuthority(PRODUCT_WRITE_SCOPE)
.pathMatchers(HttpMethod.DELETE).hasAuthority(PRODUCT_WRITE_SCOPE)
// health and info urls will be open(permitted to all) others will be checked for authorization
.matchers(EndpointRequest.to(HealthEndpoint::class.java, InfoEndpoint::class.java)).permitAll()
.anyExchange().authenticated()
.and()
.csrf().disable()
.formLogin().disable()
.oauth2ResourceServer()
.authenticationEntryPoint(authenticationEntryPoint())
.accessDeniedHandler(accessDeniedHandler())
.jwt()
.jwtAuthenticationConverter {
jwtAuthenticationConverter(it)
}
return http.build()
}
private fun jwtAuthenticationConverter(jwt: Jwt): Mono<AbstractAuthenticationToken>? {
val jwtAuthConverter = ReactiveJwtAuthenticationConverter()
jwtAuthConverter.setJwtGrantedAuthoritiesConverter {
val jwtGrantedAuthoritiesConverter = JwtAuthoritiesConverter()
val reactiveJwtGrantedAuthoritiesConverterAdapter =
ReactiveJwtGrantedAuthoritiesConverterAdapter(jwtGrantedAuthoritiesConverter)
reactiveJwtGrantedAuthoritiesConverterAdapter.convert(it)
}
return jwtAuthConverter.convert(jwt)
}
companion object {
private const val PRODUCT_WRITE_SCOPE = "SCOPE_product:write"
}
}
我面临的问题是,如果我在 GET
请求的授权 header 中发送过期令牌,令牌验证仍然会发生并且我收到令牌过期错误。
有没有办法更改配置,使令牌验证仅对某些端点发生而对其他端点忽略?
这是我为解决问题所做的工作。您可以选择指定安全配置应应用于哪些路径。这是指定的代码片段。
.securityMatcher {
ServerWebExchangeMatchers.matchers(
ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, "/**"),
ServerWebExchangeMatchers.pathMatchers(HttpMethod.PUT, "/**"),
ServerWebExchangeMatchers.pathMatchers(HttpMethod.DELETE, "/**")
).matches(it)
}
这是完整的配置。
@EnableReactiveMethodSecurity
class SecurityConfig : WebFluxConfigurer {
@Bean
fun authenticationEntryPoint(): ServerAuthenticationEntryPoint {
return JwtBearerTokenServerAuthenticationEntryPoint()
}
@Bean
fun accessDeniedHandler(): ServerAccessDeniedHandler {
return JwtTokenAccessDeniedHandler()
}
@Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
http
.securityMatcher {
ServerWebExchangeMatchers.matchers(
ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, "/**"),
ServerWebExchangeMatchers.pathMatchers(HttpMethod.PUT, "/**"),
ServerWebExchangeMatchers.pathMatchers(HttpMethod.DELETE, "/**")
).matches(it)
}
.authorizeExchange()
.pathMatchers("/docs/**", "/v2/api-docs/**", "/").permitAll()
// Client should have the required scope to write to products
.pathMatchers(HttpMethod.POST).hasAuthority(PRODUCT_WRITE_SCOPE)
.pathMatchers(HttpMethod.PUT).hasAuthority(PRODUCT_WRITE_SCOPE)
.pathMatchers(HttpMethod.DELETE).hasAuthority(PRODUCT_WRITE_SCOPE)
// health and info urls will be open(permitted to all) others will be checked for authorization
.matchers(EndpointRequest.to(HealthEndpoint::class.java, InfoEndpoint::class.java)).permitAll()
.anyExchange().authenticated()
.and()
.csrf().disable()
.formLogin().disable()
.oauth2ResourceServer()
.authenticationEntryPoint(authenticationEntryPoint())
.accessDeniedHandler(accessDeniedHandler())
.jwt()
.jwtAuthenticationConverter {
jwtAuthenticationConverter(it)
}
return http.build()
}
private fun jwtAuthenticationConverter(jwt: Jwt): Mono<AbstractAuthenticationToken>? {
val jwtAuthConverter = ReactiveJwtAuthenticationConverter()
jwtAuthConverter.setJwtGrantedAuthoritiesConverter {
val jwtGrantedAuthoritiesConverter = JwtAuthoritiesConverter()
val reactiveJwtGrantedAuthoritiesConverterAdapter =
ReactiveJwtGrantedAuthoritiesConverterAdapter(jwtGrantedAuthoritiesConverter)
reactiveJwtGrantedAuthoritiesConverterAdapter.convert(it)
}
return jwtAuthConverter.convert(jwt)
}
companion object {
private const val PRODUCT_WRITE_SCOPE = "SCOPE_product:write"
}
}
我正在将微服务配置为资源服务器,它使用 JWK 端点来验证 JWT 令牌的签名。
我已将配置设置为允许服务中的所有 GET
请求。所有其他请求都根据范围和角色进行保护。这是我正在使用的配置。
@EnableReactiveMethodSecurity
class SecurityConfig : WebFluxConfigurer {
@Bean
fun authenticationEntryPoint(): ServerAuthenticationEntryPoint {
return JwtBearerTokenServerAuthenticationEntryPoint()
}
@Bean
fun accessDeniedHandler(): ServerAccessDeniedHandler {
return JwtTokenAccessDeniedHandler()
}
@Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
http
.authorizeExchange()
.pathMatchers(HttpMethod.GET).permitAll()
.pathMatchers("/docs/**", "/v2/api-docs/**", "/").permitAll()
// Client should have the required scope to write to products
.pathMatchers(HttpMethod.POST).hasAuthority(PRODUCT_WRITE_SCOPE)
.pathMatchers(HttpMethod.PUT).hasAuthority(PRODUCT_WRITE_SCOPE)
.pathMatchers(HttpMethod.DELETE).hasAuthority(PRODUCT_WRITE_SCOPE)
// health and info urls will be open(permitted to all) others will be checked for authorization
.matchers(EndpointRequest.to(HealthEndpoint::class.java, InfoEndpoint::class.java)).permitAll()
.anyExchange().authenticated()
.and()
.csrf().disable()
.formLogin().disable()
.oauth2ResourceServer()
.authenticationEntryPoint(authenticationEntryPoint())
.accessDeniedHandler(accessDeniedHandler())
.jwt()
.jwtAuthenticationConverter {
jwtAuthenticationConverter(it)
}
return http.build()
}
private fun jwtAuthenticationConverter(jwt: Jwt): Mono<AbstractAuthenticationToken>? {
val jwtAuthConverter = ReactiveJwtAuthenticationConverter()
jwtAuthConverter.setJwtGrantedAuthoritiesConverter {
val jwtGrantedAuthoritiesConverter = JwtAuthoritiesConverter()
val reactiveJwtGrantedAuthoritiesConverterAdapter =
ReactiveJwtGrantedAuthoritiesConverterAdapter(jwtGrantedAuthoritiesConverter)
reactiveJwtGrantedAuthoritiesConverterAdapter.convert(it)
}
return jwtAuthConverter.convert(jwt)
}
companion object {
private const val PRODUCT_WRITE_SCOPE = "SCOPE_product:write"
}
}
我面临的问题是,如果我在 GET
请求的授权 header 中发送过期令牌,令牌验证仍然会发生并且我收到令牌过期错误。
有没有办法更改配置,使令牌验证仅对某些端点发生而对其他端点忽略?
这是我为解决问题所做的工作。您可以选择指定安全配置应应用于哪些路径。这是指定的代码片段。
.securityMatcher {
ServerWebExchangeMatchers.matchers(
ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, "/**"),
ServerWebExchangeMatchers.pathMatchers(HttpMethod.PUT, "/**"),
ServerWebExchangeMatchers.pathMatchers(HttpMethod.DELETE, "/**")
).matches(it)
}
这是完整的配置。
@EnableReactiveMethodSecurity
class SecurityConfig : WebFluxConfigurer {
@Bean
fun authenticationEntryPoint(): ServerAuthenticationEntryPoint {
return JwtBearerTokenServerAuthenticationEntryPoint()
}
@Bean
fun accessDeniedHandler(): ServerAccessDeniedHandler {
return JwtTokenAccessDeniedHandler()
}
@Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
http
.securityMatcher {
ServerWebExchangeMatchers.matchers(
ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, "/**"),
ServerWebExchangeMatchers.pathMatchers(HttpMethod.PUT, "/**"),
ServerWebExchangeMatchers.pathMatchers(HttpMethod.DELETE, "/**")
).matches(it)
}
.authorizeExchange()
.pathMatchers("/docs/**", "/v2/api-docs/**", "/").permitAll()
// Client should have the required scope to write to products
.pathMatchers(HttpMethod.POST).hasAuthority(PRODUCT_WRITE_SCOPE)
.pathMatchers(HttpMethod.PUT).hasAuthority(PRODUCT_WRITE_SCOPE)
.pathMatchers(HttpMethod.DELETE).hasAuthority(PRODUCT_WRITE_SCOPE)
// health and info urls will be open(permitted to all) others will be checked for authorization
.matchers(EndpointRequest.to(HealthEndpoint::class.java, InfoEndpoint::class.java)).permitAll()
.anyExchange().authenticated()
.and()
.csrf().disable()
.formLogin().disable()
.oauth2ResourceServer()
.authenticationEntryPoint(authenticationEntryPoint())
.accessDeniedHandler(accessDeniedHandler())
.jwt()
.jwtAuthenticationConverter {
jwtAuthenticationConverter(it)
}
return http.build()
}
private fun jwtAuthenticationConverter(jwt: Jwt): Mono<AbstractAuthenticationToken>? {
val jwtAuthConverter = ReactiveJwtAuthenticationConverter()
jwtAuthConverter.setJwtGrantedAuthoritiesConverter {
val jwtGrantedAuthoritiesConverter = JwtAuthoritiesConverter()
val reactiveJwtGrantedAuthoritiesConverterAdapter =
ReactiveJwtGrantedAuthoritiesConverterAdapter(jwtGrantedAuthoritiesConverter)
reactiveJwtGrantedAuthoritiesConverterAdapter.convert(it)
}
return jwtAuthConverter.convert(jwt)
}
companion object {
private const val PRODUCT_WRITE_SCOPE = "SCOPE_product:write"
}
}