在使用 Spring Boot 3 和 WebFlux 的 Kotlin 中,我有一个自定义验证器,它需要两个输入:一个是正在验证的值,但我还需要身份验证主体来验证用户是否具有对该值的合法访问权限。
使用
NullPointerException
时,我得到 getContext()
。
@Component
class OrgInstanceValidator(val validator: OrgPermissionValidator) : ConstraintValidator<ValidOrgInstance, InstanceId> {
override fun isValid(value: InstanceId, context: ConstraintValidatorContext): Boolean = runBlocking {
val accessToken = ReactiveSecurityContextHolder.getContext().map(SecurityContext::getAuthentication).map {
it.principal as Jwt
}.awaitSingle()
validator.validateInstanceAccess(accessToken.subject, value).awaitSingle()
}.isGranted
}
我也接受在控制器上使用 AOP,在此示例中值是
PathParam
。
有人有解决这个问题的经验吗?
使用
ReactiveSecurityContextHolder
似乎不起作用,降低bean优先级也不起作用。
我们放弃了尝试在反应式/Webflux 配置上使用 ConstraintValidator。
我们最终使用了大多数 RestController 注释(如 AuthenticationPrincipal、PathVariable 等)所使用的相同机制,通过创建我们自己的注释并为处理注释类的 HandlerMethodArgumentResolver 类型创建 bean:
import org.springframework.web.reactive.HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE
import java.security.Principal
...
class MethodAnnotationValidator<T : Annotation>(
adapterRegistry: ReactiveAdapterRegistry,
private val annotation: Class<T>,
private val validator: (Principal, String) -> Mono<Any>,
) : HandlerMethodArgumentResolver {
// compose this resolver to fetch the Auth context
private val principal = PrincipalMethodArgumentResolver(adapterRegistry)
// path var resolver isn't composable, next best thing
private val pathParam = { paramName: String, exchange: ServerWebExchange -> exchange
.getAttributeOrDefault(URI_TEMPLATE_VARIABLES_ATTRIBUTE, emptyMap<Any, Any>())
.get(paramName)!!}
// resolve Principal and PathParam and call validator()
// inside resolveArgument() override
...