Why doesn't @RestCookie detect a Cookie Header set in the ContainerRequestFilter for resteasy-reactive?

huangapple go评论49阅读模式
英文:

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

huangapple
  • 本文由 发表于 2023年5月18日 12:27:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76277730.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定