身份验证插件:JWT 与会话
使用 JWT 持有者令牌和基于会话的身份验证保护 Ktor 路由。
身份验证插件:JWT 与会话 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。
Ktor 身份验证概述
Ktor 的 Authentication 插件为保护路由提供了统一的 API。您可以配置一个或多个提供程序(JWT、Session、Basic、OAuth 等),然后将路由包裹在 authenticate("providerName") { } 块中。
添加身份验证依赖项
将身份验证库和 JWT 库添加到您的构建配置中:
dependencies {
implementation("io.ktor:ktor-server-auth:2.3.12")
implementation("io.ktor:ktor-server-auth-jwt:2.3.12")
implementation("io.ktor:ktor-server-sessions:2.3.12")
}配置 JWT 身份验证
安装 Authentication 插件并配置 JWT 提供程序。verifier 用于验证令牌签名,validate 用于从有效载荷中提取主体:
install(Authentication) {
jwt("auth-jwt") {
realm = "ktor app"
verifier(
JWT.require(Algorithm.HMAC256(secret))
.withAudience(audience)
.withIssuer(issuer)
.build()
)
validate { credential ->
if (credential.payload.getClaim("username").asString() != null)
JWTPrincipal(credential.payload)
else null
}
}
}使用 JWT 保护路由
将任意路由组包裹在 authenticate("auth-jwt") { } 中。未经身份验证的请求会自动收到 401 响应:
routing {
authenticate("auth-jwt") {
get("/protected") {
val principal = call.principal<JWTPrincipal>()!!
val username = principal.payload.getClaim("username").asString()
call.respondText("Hello, $username")
}
}
}签发 JWT 令牌
在登录端点中使用 java-jwt 库生成并签署 JWT:
post("/login") {
val user = call.receive<LoginRequest>()
// validate credentials ...
val token = JWT.create()
.withAudience(audience)
.withIssuer(issuer)
.withClaim("username", user.username)
.withExpiresAt(Date(System.currentTimeMillis() + 3_600_000))
.sign(Algorithm.HMAC256(secret))
call.respond(mapOf("token" to token))
}会话身份验证
会话在服务器端存储用户状态(或者以已签名 Cookie 的形式存储在客户端)。请安装 Sessions 插件,并定义会话数据类:
data class UserSession(val userId: Long, val username: String)
install(Sessions) {
cookie<UserSession>("user_session") {
cookie.path = "/"
cookie.httpOnly = true
}
}配置会话身份验证提供程序
创建一个会话身份验证提供程序,用于读取会话并返回主体:
install(Authentication) {
session<UserSession>("auth-session") {
validate { session -> session }
challenge { call.respond(HttpStatusCode.Unauthorized) }
}
}设置和清除会话
登录后使用 call.sessions.set() 设置会话,退出登录时使用 call.sessions.clear 清除会话:
post("/login") {
val creds = call.receive<LoginRequest>()
// validate ...
call.sessions.set(UserSession(userId = 1L, username = creds.username))
call.respond(HttpStatusCode.OK)
}
post("/logout") {
call.sessions.clear<UserSession>()
call.respond(HttpStatusCode.OK)
}JWT 与会话:分别适用于何时
JWT:无状态,适合由移动客户端或 SPA 使用的 API。令牌包含所有声明,服务器无需会话存储。会话:有状态,适合服务端渲染的 Web 应用。Cookie 中存储会话 ID,服务器保存会话数据(内存、Redis 或数据库)。
组合多个身份验证提供程序
您可以定义多个提供程序,并使用 authenticate("jwt", "session") { } 要求其中任意一个提供程序通过验证。Ktor 会按顺序尝试每个提供程序,只要有一个验证成功,就会接受该请求。
自定义质询响应
每个提供程序都有一个 challenge 块,用于定义身份验证失败时的处理方式。您可以返回包含 JSON 错误正文的 401 响应,而不是默认的 WWW-Authenticate 标头:
jwt("auth-jwt") {
// ...
challenge { _, _ ->
call.respond(HttpStatusCode.Unauthorized, mapOf("error" to "Token expired or invalid"))
}
}快速检查
Ktor JWT 提供程序中的 validate 块有什么作用?
回顾:身份验证插件——JWT 与会话
要点:
- 安装
Authentication,并配置提供程序(jwt、session、basic、oauth) - 使用
authenticate("providerName") { }保护路由 - JWT:无状态令牌;在登录时签名,使用验证器验证,并在
validate中读取声明 - 会话:有状态;登录时使用
call.sessions.set(),退出登录时使用clear() - 使用
challenge自定义 401 响应的格式
常见问题解答
「身份验证插件:JWT 与会话」课时是免费的吗?
是的 — 「身份验证插件:JWT 与会话」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。
「身份验证插件:JWT 与会话」这节课中我会学到什么?
使用 JWT 持有者令牌和基于会话的身份验证保护 Ktor 路由。 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Kotlin Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「身份验证插件:JWT 与会话」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Kotlin Academy 课中编写并运行代码吗?
能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。