我正在尝试在Spring WebFlux应用程序中设置JWT与Spring Security的身份验证。我正在使用基于自定义JWT声明的自定义授权方案。我遇到的问题是,当我尝试调用安全端点时,Authentication failed: An Authentication object was not found in the SecurityContext
身份验证失败。
下面是我使用的SecurityWebFilterChain
:
@Configuration
@EnableWebFluxSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
class WebSecurityConfiguration {
@Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
return http {
authorizeExchange {
authorize(anyExchange, authenticated)
}
oauth2ResourceServer {
jwt {
jwtAuthenticationConverter = grantedAuthoritiesExtractor()
}
}
}
}
fun grantedAuthoritiesExtractor(): Converter<Jwt, Mono<AbstractAuthenticationToken>> {
val jwtAuthenticationConverter = JwtAuthenticationConverter()
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(MappingJwtAuthoritiesConverter())
// custom JWT -> Collection<GrantedAuthority> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter)
}
@Bean
fun jwtDecoder(): ReactiveJwtDecoder {
val secretKey: SecretKey = SecretKeySpec("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".toByteArray(), "HMACSHA256")
return NimbusReactiveJwtDecoder.withSecretKey(secretKey).macAlgorithm(MacAlgorithm.HS256).build()
}
@Bean
fun jwtValidator(): OAuth2TokenValidator<Jwt> {
return OAuth2TokenValidator<Jwt> { OAuth2TokenValidatorResult.success() }
}
fun jwtAuthenticationManager(jwtDecoder: ReactiveJwtDecoder): JwtReactiveAuthenticationManager {
return JwtReactiveAuthenticationManager(jwtDecoder).apply {
this.setJwtAuthenticationConverter(grantedAuthoritiesExtractor())
}
}
}
下面是MappingJwtAuthoritiesConverter
:
class MappingJwtAuthoritiesConverter : Converter<Jwt, Collection<GrantedAuthority>> {
companion object {
private val WELL_KNOWN_CLAIMS: Set<String> = setOf("myCustomClaim")
}
override fun convert(jwt: Jwt): Collection<GrantedAuthority> {
val authorities = jwt.claims.entries
.filter { (key, _) -> key in WELL_KNOWN_CLAIMS }
.map { (key, value) ->
return@map SimpleGrantedAuthority("$key:$value")
}
return authorities
}
}
我在网上搜索了一下,但是很多JWT/Spring Webflux实现都是手工进行JWT验证和处理的,我更愿意使用Spring在OAuth集成下已经提供的东西。现在我唯一使用的定制部分是从JWT到GrantedAuthority
的转换器,但是我仍然不能让验证工作。
使用以下JWT:
header:
{
"typ": "JWT",
"alg": "HS256"
}
payload:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1658474926,
"exp": 1668478526,
"myCustomClaim": "READ"
}
已编码:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNjU4NDc0OTI2LCJleHAiOjE2Njg0Nzg1MjYsIm15Q3VzdG9tQ2xhaW0iOiJSRUFEIn0.lh66pHMd_xvXAF2itblHeHbZReJQA5xkGLKqXZV6MjI
我尝试保护的端点定义为:
@RestController
class FooController {
@PreAuthorize("hasAuthority('myCustomClaim:READ')")
@RequestMapping(
method = [RequestMethod.GET],
value = ["/foo"],
)
override suspend fun getFoo(): ResponseEntity<String> {
return ResponseEntity.ok("Got foo")
}
}
Spring日志:
2022-07-22 09:43:35.138 DEBUG 508191 --- [ctor-http-nio-2] o.s.w.s.adapter.HttpWebHandlerAdapter : [b7fe0c9e-1] HTTP GET "/foo"
2022-07-22 09:43:35.313 DEBUG 508191 --- [ parallel-2] o.s.w.s.s.DefaultWebSessionManager : Created new WebSession.
2022-07-22 09:43:35.319 DEBUG 508191 --- [ parallel-2] o.s.s.w.s.u.m.OrServerWebExchangeMatcher : Trying to match using org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers$1@3602a026
2022-07-22 09:43:35.319 DEBUG 508191 --- [ parallel-2] o.s.s.w.s.u.m.OrServerWebExchangeMatcher : matched
2022-07-22 09:43:35.319 DEBUG 508191 --- [ parallel-2] a.DelegatingReactiveAuthorizationManager : Checking authorization on '/foo' using org.springframework.security.authorization.AuthenticatedReactiveAuthorizationManager@2668fdab
2022-07-22 09:43:35.320 DEBUG 508191 --- [ parallel-2] o.s.s.w.s.a.AuthorizationWebFilter : Authorization successful
2022-07-22 09:43:35.325 DEBUG 508191 --- [ parallel-2] s.w.r.r.m.a.RequestMappingHandlerMapping : [b7fe0c9e-1] Mapped to it.project.backend.controllers.FooController#getFoo(Continuation)
2022-07-22 09:43:35.665 DEBUG 508191 --- [ parallel-2] o.s.s.w.s.a.AuthenticationWebFilter : Authentication failed: An Authentication object was not found in the SecurityContext
2022-07-22 09:43:35.694 DEBUG 508191 --- [ parallel-2] o.s.w.s.adapter.HttpWebHandlerAdapter : [b7fe0c9e-1] Completed 401 UNAUTHORIZED
有什么想法吗?
2条答案
按热度按时间ttcibm8c1#
问题是在配置bean中使用
@EnableGlobalMethodSecurity
而不是@EnableReactiveMethodSecurity
。修复后,一切都开始工作。3vpjnl9f2#
看起来您构建
jwtDecoder
时使用的密钥与您发布的令牌的签名不对应,因此令牌验证失败。您可以使用https://jwt.io/进行检查。