英文:
Why doesn't @RestCookie detect a Cookie Header set in the ContainerRequestFilter for resteasy-reactive?
问题
Here's the translated code you provided:
我正在迁移我的 Kotlin Quarkus 应用程序,以使用 `quarkus-rest-client` 和 `quarkus-resteasy` 的响应式版本。
基本上,我希望在用户没有在其请求中提供 Cookie 的情况下,创建一个包含 JWT 的 Cookie 并设置在 User-Agent 上,只有在 `ApiResource` 中定义的端点(因此使用自定义的 `@NameBinding`) - 然后,同一 User-Agent 的后续请求会自动获得此 Cookie。
这是我之前的大致代码,使用 Resteasy Classic:
``` kotlin
import org.eclipse.microprofile.rest.client.inject.RestClient
import javax.inject.Inject
import javax.ws.rs.*
import javax.ws.rs.core.*
import javax.ws.rs.container.*
import javax.ws.rs.ext.Provider
val RESOURCE_PATH = "/api"
@NameBinding
@Retention(AnnotationRetention.RUNTIME)
annotation class JwtCookieUpserterBinder
@JwtCookieUpserterBinder
@Provider
class JwtCookieUpserter: ContainerRequestFilter, ContainerResponseFilter {
  @Inject
  @RestClient
  lateinit var jwtService: JwtClient
  override fun filter(requestContext: ContainerRequestContext) {
    var jwtCookie = requestContext?.cookies?.get("jwt")
    if (jwtCookie == null || jwtCookie.value.isNullOrEmpty()) {
      val newJwt: String = jwtService.getJwt() // 返回一个字符串
      jwtCookie = NewCookie("jwt", newJwt, RESOURCE_PATH, null, null, 600, false)
      requestContext?.headers?.add(HttpHeaders.COOKIE, jwtCookie.toString())
      requestContext?.setProperty("jwt", jwtCookie)
    }
  }
  override fun filter(requestContext: ContainerRequestContext, responseContext: ContainerResponseContext) {
    val jwtCookie = requestContext?.getProperty("jwt")
    if (jwtCookie != null) {
      responseContext?.headers?.add(HttpHeaders.SET_COOKIE, jwtCookie.toString())
    }
  }
}
@JwtCookieUpserterBinder
@Path(RESOURCE_PATH)
class ApiResource {
  // ...其他资源端点...
  // 用于测试的路由
  @GET
  @Path("/jwt")
  @Produces(MediaType.TEXT_PLAIN)
  fun getJwt(
    @CookieParam("jwt") jwtCookieValue: String?
  ): Response {
    return Response.ok(jwtCookieValue, MediatType.TEXT_PLAIN).build()
  }
  // ...其他资源端点...
}
上述实现之前是正常工作的。但是,切换到 resteasy-reactive 后,我注意到在 RequestFilter 中设置 Cookie HttpHeader 不再起作用,我不得不在 ApiResource 中的 ContainerRequestContext 属性中提取 Cookie 值。现在,以下是我当前的 Resteasy Reactive 代码:
import javax.enterprise.context.ApplicationScoped
import org.eclipse.microprofile.rest.client.inject.RestClient
import javax.inject.Inject
import javax.ws.rs.*
import javax.ws.rs.core.*
import javax.ws.rs.container.*
import javax.ws.rs.ext.Provider
import org.jboss.resteasy.reactive.*
import org.jboss.resteasy.reactive.server.*
val RESOURCE_PATH = "/api"
@NameBinding
@Retention(AnnotationRetention.RUNTIME)
annotation class JwtCookieUpserterBinder
@ApplicationScoped
@Provider
class JwtCookieUpserter {
  @RestClient
  lateinit var jwtService: JwtClient
  @JwtCookieUpserterBinder
  @ServerRequestFilter
  fun filterRequest(requestContext: ContainerRequestContext?) {
    var jwtCookie = requestContext?.cookies?.get("jwt")
    if (jwtCookie == null || jwtCookie.value.isNullOrEmpty()) {
      val newJwt: String = jwtService.getJwt() // 返回一个字符串
      jwtCookie = NewCookie("jwt", newJwt, RESOURCE_PATH, null, null, 600, false)
      // requestContext?.headers?.add(HttpHeaders.COOKIE, jwtCookie.toString()) // 这在 ApiResource 中似乎不再起作用
      requestContext?.setProperty("set-jwt", jwtCookie)
    }
    requestContext?.setProperty("jwt", jwtCookie)
  }
  @JwtCookieUpserterBinder
  @ServerResponseFilter
  fun filterResponse(requestContext: ContainerRequestContext, responseContext: ContainerResponseContext) {
    val jwtCookie = requestContext?.getProperty("set-jwt")
    if (jwtCookie != null) {
      responseContext?.headers?.add(HttpHeaders.SET_COOKIE, jwtCookie.toString())
    }
  }
}
@JwtCookieUpserterBinder
@ApplicationScoped
@Path(RESOURCE_PATH)
class ApiResource {
  @Inject
  lateinit var requestContext: ContainerRequestContext
  // ...其他资源端点...
  private fun getJwtCookieValueFromRequestContext(): String {
    return (requestContext.getProperty("jwt") as? Cookie)?.value ?: "Not Set"
  }
  // 用于测试的路由
  @GET
  @Path("/jwt")
  @Produces(MediaType.TEXT_PLAIN)
  fun getJwt(
    @RestCookie("jwt") jwt: String? // 对于用户代理提供请求中的 Cookie 值,似乎仍然需要这个
  ): Response {
    val jwtCookieValue = getJwtCookieValueFromRequestContext()
    return Response.ok(jwtCookieValue, MediatType.TEXT_PLAIN).build()
  }
  // ...其他资源端点...
}
我不确定这是否是实现我想要的正确方式(将 ContainerRequestFilter 注入到 ApiResource Bean 中似乎有些奇怪);但我主要好奇为什么 @RestCookie 似乎与 @CookieParam 表现不同。
或者,如果有人对在不添加额外依赖的情况下更好地完成此任务有建议,我也愿意听取建议。
英文:
I'm in the middle of migrating my Kotlin Quarkus Application to use the Reactive versions of quarkus-rest-client and quarkus-resteasy.
Basically, I want a Cookie containing a JWT to be created and set on the User-Agent if they did not provide it in their Request to any of the Endpoints defined in ApiResource only (hence the custom @NameBinding) - subsequent Requests by the same User-Agent would then give this Cookie automatically.
This was my approximate code before, using Resteasy Classic:
import org.eclipse.microprofile.rest.client.inject.RestClient
import javax.inject.Inject
import javax.ws.rs.*
import javax.ws.rs.core.*
import javax.ws.rs.container.*
import javax.ws.rs.ext.Provider
val RESOURCE_PATH = "/api"
@NameBinding
@Retention(AnnotationRetention.RUNTIME)
annotation class JwtCookieUpserterBinder
@JwtCookieUpserterBinder
@Provider
class JwtCookieUpserter: ContainerRequestFilter, ContainerResponseFilter {
  @Inject
  @RestClient
  lateinit var jwtService: JwtClient
  override fun filter(requestContext: ContainerRequestContext) {
    var jwtCookie = requestContext?.cookies?.get("jwt")
    if (jwtCookie == null || jwtCookie.value.isNullOrEmpty()) {
      val newJwt: String = jwtService.getJwt() // returns a String
      jwtCookie = NewCookie("jwt", newJwt, RESOURCE_PATH, null, null, 600, false)
      requestContext?.headers?.add(HttpHeaders.COOKIE, jwtCookie.toString())
      requestContext?.setProperty("jwt", jwtCookie)
    }
  }
  override fun filter(requestContext: ContainerRequestContext, responseContext: ContainerResponseContext) {
    val jwtCookie = requestContext?.getProperty("jwt")
    if (jwtCookie != null) {
      responseContext?.headers?.add(HttpHeaders.SET_COOKIE, jwtCookie.toString())
    }
  }
}
@JwtCookieUpserterBinder
@Path(RESOURCE_PATH)
class ApiResource {
  // ...
  // Route meant for Testing
  @GET
  @Path("/jwt")
  @Produces(MediaType.TEXT_PLAIN)
  fun getJwt(
    @CookieParam("jwt") jwtCookieValue: String?
  ): Response {
    return Response.ok(jwtCookieValue, MediatType.TEXT_PLAIN).build()
  }
  // ... other Resource Endpoints ...
}
The above implementation was working correctly. After switching to resteasy-reactive however, I notice that setting the Cookie HttpHeader in the RequestFilter no longer works, and I ended up having to pull the Cookie value from a property on ContainerRequestContext within ApiResource instead. This is my current code now, for Resteasy Reactive:
import javax.enterprise.context.ApplicationScoped
import org.eclipse.microprofile.rest.client.inject.RestClient
import javax.inject.Inject
import javax.ws.rs.*
import javax.ws.rs.core.*
import javax.ws.rs.container.*
import javax.ws.rs.ext.Provider
import org.jboss.resteasy.reactive.*
import org.jboss.resteasy.reactive.server.*
val RESOURCE_PATH = "/api"
@NameBinding
@Retention(AnnotationRetention.RUNTIME)
annotation class JwtCookieUpserterBinder
@ApplicationScoped
@Provider
class JwtCookieUpserter {
  @RestClient
  lateinit var jwtService: JwtClient
  @JwtCookieUpserterBinder
  @ServerRequestFilter
  fun filterRequest(requestContext: ContainerRequestContext?) {
    var jwtCookie = requestContext?.cookies?.get("jwt")
    if (jwtCookie == null || jwtCookie.value.isNullOrEmpty()) {
      val newJwt: String = jwtService.getJwt() // returns a String
      jwtCookie = NewCookie("jwt", newJwt, RESOURCE_PATH, null, null, 600, false)
      // requestContext?.headers?.add(HttpHeaders.COOKIE, jwtCookie.toString()) // this no longer seems to have any effect in ApiResource
      requestContext?.setProperty("set-jwt", jwtCookie)
    }
    requestContext?.setProperty("jwt", jwtCookie)
  }
  @JwtCookieUpserterBinder
  @ServerResponseFilter
  fun filterResponse(requestContext: ContainerRequestContext, responseContext: ContainerResponseContext) {
    val jwtCookie = requestContext?.getProperty("set-jwt")
    if (jwtCookie != null) {
      responseContext?.headers?.add(HttpHeaders.SET_COOKIE, jwtCookie.toString())
    }
  }
}
@JwtCookieUpserterBinder
@ApplicationScoped
@Path(RESOURCE_PATH)
class ApiResource {
  @Inject
  lateinit var requestContext: ContainerRequestContext
  // ...
  private fun getJwtCookieValueFromRequestContext(): String {
    return (requestContext.getProperty("jwt") as? Cookie)?.value ?: "Not Set"
  }
  // Route meant for Testing
  @GET
  @Path("/jwt")
  @Produces(MediaType.TEXT_PLAIN)
  fun getJwt(
    @RestCookie("jwt") jwt: String? // This still seems necessary for the Endpoint to take in the User-Agent's Cookie Value if they provide it in the Request
  ): Response {
    val jwtCookieValue = getJwtCookieValueFromRequestContext()
    return Response.ok(jwtCookieValue, MediatType.TEXT_PLAIN).build()
  }
  // ... other Resource Endpoints ...
}
I'm not sure if this is the correct way to accomplish what I want (injecting the ContainerRequestFilter into the ApiResource Bean seems weird); but I am primarily curious on why @RestCookie seems to behave differently than @CookieParam.
Alternatively, if anyone has suggestions on a better way to accomplish this without adding additional Dependencies, I am open to those as well.
答案1
得分: 1
这实际上是一个bug。但修复将很快可用。
英文:
This is actually a bug. But the fix will be available very soon
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论