我正在迁移我的 Kotlin Quarkus 应用程序以使用
quarkus-rest-client
和 quarkus-resteasy
的 Reactive 版本。
基本上,我想要一个包含 JWT 的 Cookie 创建并在用户代理上设置,如果他们没有在他们的请求中提供它到
ApiResource
中定义的任何端点(因此自定义 @NameBinding
) - 后续同一用户代理的请求将自动提供此 Cookie。
这是我之前大概的代码,使用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 ...
}
上面的实现工作正常。然而,切换到
resteasy-reactive
后,我注意到在 RequestFilter
中设置 Cookie HttpHeader 不再有效,我最终不得不从 ContainerRequestContext
内的 ApiResource
上的属性中提取 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() // 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 ...
}
我不确定这是否是完成我想要的事情的正确方法(将
ContainerRequestFilter
注入 ApiResource
Bean 看起来很奇怪);但我主要好奇为什么 @RestCookie
的行为似乎与 @CookieParam
不同。
或者,如果有人对在不添加额外依赖项的情况下完成此任务的更好方法提出建议,我也愿意接受。