在 Ktor 0.9.0 servlet 中控制 cookie 生命周期

Posted

技术标签:

【中文标题】在 Ktor 0.9.0 servlet 中控制 cookie 生命周期【英文标题】:Controlling cookie lifecycle in Ktor 0.9.0 servlet 【发布时间】:2018-04-27 16:55:20 【问题描述】:

我在删除由 Ktor 0.9.0 服务器端应用程序设置的 cookie 时遇到问题。可能我不知道怎么做才对,或者Ktor框架有遗漏。

cookie 创建和删除本身不是问题,但为了删除 cookie,我必须使用与客户端浏览器上的 cookie 一起存储的相同路径。 Ktor 让我通过 cookie 创建来控制路径。这是我的配置:

install(Sessions) 
    cookie<MySession>(sessionMarker) 
        cookie.duration = cookieDuration
        cookie.path = "/myWebapp"
        transform(SessionTransportTransformerMessageAuthentication(sessionKey))
    

在登录页面 /myWebapp/page/login 上,我创建了 cookie,然后将其发送到客户端,并为发送到 Web 应用程序的其余请求来回传输:

call.sessions.set(MySession([some data class arguments]))

在客户端检查时,cookie 会显示路径 /myWebapp。默认值为/myWebapp/page,因为这是登录页面的路径,但该路径取自上面显示的cookie 配置。到目前为止一切都很好。

最终用户想通过 POST 请求退出登录页面:

call.sessions.clear<MySession>()

这里的问题是我还没有找到控制 cookie 路径的方法。因为登录页面 /myWebapp/page/login 正在将过期的 cookie 发送回客户端以获得另一个路径(它自己的 /myWebapp/page),所以原始 cookie 不会被删除(/myWebapp/page != /myWebapp)。

尝试删除时如何控制 Ktor 0.9.0 中 cookie 的路径?

我知道如何解决它:通过创建具有相同路径的 cookie,我将从中删除它。但这不是我想要的(Web 应用程序中还有其他路径,如 /myWebapp/others 应该使用 cookie)。在创建过程中控制 cookie 路径的能力没有任何意义。

【问题讨论】:

【参考方案1】:

我认为您可以尝试创建自己的自定义 SessionTransportCookie。

如果您更深入地了解方法cookie&lt;MySession&gt;(sessionMarker),您会发现以下代码:

inline fun <reified S : Any> Sessions.Configuration.cookie(name: String, block: CookieSessionBuilder<S>.() -> Unit): Unit = cookie(name, S::class, block)

inline fun <S : Any> Sessions.Configuration.cookie(name: String, sessionType: KClass<S>, block: CookieSessionBuilder<S>.() -> Unit) 
    val builder = CookieSessionBuilder(sessionType).apply(block)
    val transport = SessionTransportCookie(name, builder.cookie, builder.transformers)
    val tracker = SessionTrackerByValue(sessionType, builder.serializer)
    val provider = SessionProvider(name, sessionType, transport, tracker)
    register(provider)

这里重要的一行是按行创建会话传输cookie:SessionTransportCookie(name, builder.cookie, builder.transformers)

让我们深入了解SessionTransportCookie

class SessionTransportCookie(val name: String,
                             val configuration: CookieConfiguration,
                             val transformers: List<SessionTransportTransformer>
) : SessionTransport 

    override fun receive(call: ApplicationCall): String? 
        return transformers.transformRead(call.request.cookies[name])
    

    override fun send(call: ApplicationCall, value: String) 
        val now = LocalDateTime.now()
        val expires = now.plus(configuration.duration)
        val maxAge = configuration.duration[ChronoUnit.SECONDS].toInt()
        val cookie = Cookie(name,
                transformers.transformWrite(value),
                configuration.encoding,
                maxAge,
                expires,
                configuration.domain,
                configuration.path,
                configuration.secure,
                configuration.httpOnly,
                configuration.extensions
        )

        call.response.cookies.append(cookie)
    

    override fun clear(call: ApplicationCall) 
        call.response.cookies.appendExpired(name)
    


class CookieConfiguration 
    var duration: TemporalAmount = Duration.ofDays(7)
    var encoding: CookieEncoding = CookieEncoding.URI_ENCODING
    var domain: String? = null
    var path: String? = null
    var secure: Boolean = false
    var httpOnly: Boolean = false
    val extensions: MutableMap<String, String?> = mutableMapOf()

因此,如您所见,在本课程中,您可以自定义 cookie send/clear 逻辑。

【讨论】:

以上是关于在 Ktor 0.9.0 servlet 中控制 cookie 生命周期的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Ktor 中注册一个 servlet?

Ktor 和远程 tomcat 部署

在 Ktor 客户端中编码 URL

Oauth2 授权路由在 Ktor 中不起作用

Ktor 与 Spring Boot WebFlux web api

如何使用 ktor 客户端设置 HttpServletResponse 的主体