我对 Rails 以及 KotlinJs 相当熟悉,但我对 auth 还很陌生,而且我很困惑。
我设置了 Rails Devise,并按照在线教程添加了 JWT,只是我只使用了用户名和密码。我还设置了 Ktor 前端,如下所示:
const val backend = "http://localhost:3000"
val bearerTokenStorage = mutableListOf<BearerTokens>()
suspend fun login(username: String, password: String): Pair<HttpStatusCode, Json> {
val client = HttpClient(Js) {
install(Logging)
install(ContentNegotiation) { json(Json) }
install(HttpCookies)
// install(Auth) {
// bearer {
// loadTokens {
// bearerTokenStorage.last()
// }
// }
// }
}
val userData = User(user = UserData(username = username, password = password))
val response: HttpResponse = client.post("$backend/users/sign_in") {
headers {
append(HttpHeaders.AccessControlAllowOrigin, "*")
append("Credentials", "include")
}
contentType(ContentType.Application.Json)
setBody(userData)
}
console.log("Cookies: ", client.cookies("http://0.0.0.0:3000/"), client.cookies("http://0.0.0.0:8080/")) // returns null
if (response.status == HttpStatusCode.OK) {
val token = response.headers[HttpHeaders.Authorization]
console.log("Authorization Header: $token, ${bearerTokenStorage.firstOrNull()}") //returns null
// Handle successful authentication
} else {
console.log("auth failed")
// Handle authentication failure
}
// val jwtToken = client.readToken(response)?.getClaim("yourClaimName")?.asString()
println(response.bodyAsText())
client.close()
return Pair(response.status, JSON.parse(response.body()))
}
suspend fun getDataFromInputsAndSend(inputsContainer: HTMLElement): Json {
with(inputsContainer) {
val entries = rows.map { row ->
SaveEntries(
startTime = row.startTimeInput.value,
endTime = row.endTimeInput.value
)
}
val toSend = SaveData(...entries)
println(toSend)
return sendData(toSend)
}
}
suspend fun sendData(toSend: SaveData): Json {
val client = HttpClient(Js) {
install(ContentNegotiation) { json(Json) }
install(HttpCookies)
// install(Auth) {
// bearer {
// loadTokens {
// bearerTokenStorage.last()
// }
// }
// }
}
val response: HttpResponse = client.post("$backend/maslas") {
headers {
append(HttpHeaders.AccessControlAllowOrigin, "*")
append("Credentials", "include")
}
contentType(ContentType.Application.Json)
setBody(toSend)
}
return JSON.parse(response.body())
}
当我登录成功时,响应有:
Authorization: Bearer eyJhb...
以及Set-Cookie: _backend_session=%2F1vT...%3D%3D; path=/; HttpOnly; SameSite=Lax
。有人告诉我 Set-Cookie 应该通过 JS FetchApi 保存在浏览器中 Credentials: Include
但我不知道如何在 Ktor 中做到这一点。有人建议通过正文发送令牌,尽管我几乎可以肯定这是错误的解决方案,但如果我知道如何做到这一点,我愿意尝试。
经过长时间的研究,我意识到我的错误出在 Rails 后端:我按照说明暴露了标头
'Authorization'
,但我在错误的函数 'Cors' initializer
中暴露了它,而不是正如我所期望的那样。一旦我正确地暴露了标头,Ktor 也能够看到它,并且我能够根据需要存储和检索它。我最终的 Ktor 代码只有:
middleware