【问题标题】:How to fix 403 when using keycloak JWT token with spring security使用带有spring security的keycloak JWT令牌时如何修复403
【发布时间】:2021-05-01 05:21:13
【问题描述】:
  • 我已经用 Spring SecurityKeycloak 配置了一个 Spring Boot 项目
  • 我正在从 Keycloak 服务器获取令牌
  • 当我在应用程序中调用端点时,我得到 403 和令牌
  • 代码如下:
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
class SecurityConfig {

    @Bean
    fun reactiveJwtDecoder() = NimbusReactiveJwtDecoder {
        val claimsSet = it.jwtClaimsSet
        println(Gson().toJson(claimsSet))
        Mono.just(claimsSet)
    }

    @Bean
    fun configure(
        http: ServerHttpSecurity,
        authenticationConverter: KeycloakReactiveJwtAuthenticationConverter
    ): SecurityWebFilterChain = http.apply {
        headers().frameOptions().disable()
            .and().csrf().disable()
            .authorizeExchange()
            .pathMatchers("/v/*").permitAll()
            .anyExchange().authenticated()
            .and()
            .oauth2ResourceServer()
            .jwt()
            .jwtAuthenticationConverter(authenticationConverter)
    }.build()

    @Bean
    fun clientRegistration(): ReactiveClientRegistrationRepository =
        InMemoryReactiveClientRegistrationRepository(
            ClientRegistrations.fromOidcIssuerLocation("http://localhost:8080/auth/realms/demo")
                .clientId("demo")
                .clientSecret("2de854c0-57a7-42f1-8a07-01773301646f")
                .build()
        )

}


@Component
class KeycloakReactiveJwtAuthenticationConverter : Converter<Jwt, Mono<AbstractAuthenticationToken>> {

    override fun convert(jwt: Jwt): Mono<AbstractAuthenticationToken>? {
        return Mono.just(AuthenticationToken(jwt))
    }
}

fun convert(jwt: Jwt): Collection<GrantedAuthority>? {
    @Suppress("UNCHECKED_CAST")
    val realmAccess = jwt.claims["realm_access"] as? Map<String, List<String>> ?: emptyMap()
    val roles = realmAccess.getOrDefault("roles", listOf()).map { "ROLE_$it" }
    return AuthorityUtils.createAuthorityList(*roles.toTypedArray())
}

data class AuthenticationToken(
    val jwt: Jwt
) : AbstractAuthenticationToken(convert(jwt)) {
    override fun getCredentials(): Any = ClientInfo(
        clientId = jwt.getClaimAsString("client_id")
    )
    override fun getPrincipal(): Any = ClientInfo(
        clientId = jwt.getClaimAsString("client_id")
    )
}

data class ClientInfo(
    val clientId: String
)

被传递的Json

{"claims":{"sub":"ba95843a-4ba8-4247-b2b9-4db993de7371","resource_access":{"demo":{"roles":["uma_protection"]},"account":{"roles":["manage-account","manage-account-links","view-profile"]}},"clientId":"demo","email_verified":false,"clientHost":"127.0.0.1","iss":"http://localhost:8080/auth/realms/demo","typ":"Bearer","preferred_username":"service-account-demo","clientAddress":"127.0.0.1","client_id":"demo","aud":["account"],"acr":"1","realm_access":{"roles":["offline_access","uma_authorization","USER"]},"azp":"demo","scope":"profile email","exp":"Jan 27, 2021, 5:15:29 PM","iat":"Jan 27, 2021, 5:10:29 PM","jti":"51831211-7831-4bdd-9e31-d0ba2aa7f733"}}
  • 调试日志
2021-01-27 23:41:47.896 DEBUG 14484 --- [oundedElastic-1] o.s.w.s.s.DefaultWebSessionManager       : Created new WebSession.
2021-01-27 23:41:47.899 DEBUG 14484 --- [oundedElastic-1] o.s.s.w.s.u.m.OrServerWebExchangeMatcher : Trying to match using PathMatcherServerWebExchangeMatcher{pattern='/logout', method=POST}
2021-01-27 23:41:47.900 DEBUG 14484 --- [oundedElastic-1] athPatternParserServerWebExchangeMatcher : Request 'GET /demo' doesn't match 'POST /logout'
2021-01-27 23:41:47.900 DEBUG 14484 --- [oundedElastic-1] o.s.s.w.s.u.m.OrServerWebExchangeMatcher : No matches found
2021-01-27 23:41:47.901 DEBUG 14484 --- [oundedElastic-1] a.DelegatingReactiveAuthorizationManager : Checking authorization on '/demo' using org.springframework.security.authorization.AuthenticatedReactiveAuthorizationManager@6d47f864
2021-01-27 23:41:47.903 DEBUG 14484 --- [oundedElastic-1] o.s.s.w.s.a.AuthorizationWebFilter       : Authorization failed: Access Denied
2021-01-27 23:41:47.911 DEBUG 14484 --- [oundedElastic-1] o.s.w.s.adapter.HttpWebHandlerAdapter    : [53903720-1] Completed 403 FORBIDDEN

这里有什么问题?

【问题讨论】:

    标签: spring spring-security keycloak


    【解决方案1】:
    https://stackoverflow.com/questions/61345957/spring-security-returns-403-with-valid-jwt
    

    这里的第一个答案提供了解决方案

    • 我的确切代码
    class CustomJwtAuthenticationConverter : Converter<Jwt, Mono<AbstractAuthenticationToken>> {
        private val jwtGrantedAuthoritiesConverter = JwtGrantedAuthoritiesConverter()
    
        override fun convert(source: Jwt): Mono<AbstractAuthenticationToken> {
            val authorities = source.getClaimAsString("authorities")?.split(",")?.map { SimpleGrantedAuthority(it) }
            return Mono.just(JwtAuthenticationToken(source, authorities.orEmpty()))
        }
    }
    

    【讨论】:

    • 我有相同的堆栈跟踪,但我什至没有使用 OAuth。可能是什么问题?
    猜你喜欢
    • 2018-09-21
    • 2016-04-25
    • 2016-03-22
    • 2022-11-11
    • 2017-11-02
    • 2017-11-09
    • 2022-12-07
    • 2020-08-04
    • 1970-01-01
    相关资源
    最近更新 更多