Rails 后端和 KotlinJs Ktor 前端,尝试使用 DeviseJWT 实现身份验证

问题描述 投票:0回答:1

我对 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 中做到这一点。有人建议通过正文发送令牌,尽管我几乎可以肯定这是错误的解决方案,但如果我知道如何做到这一点,我愿意尝试。

ruby-on-rails bearer-token ktor devise-jwt
1个回答
0
投票

经过长时间的研究,我意识到我的错误出在 Rails 后端:我按照说明暴露了标头

'Authorization'
,但我在错误的函数
'Cors' initializer
中暴露了它,而不是正如我所期望的那样。一旦我正确地暴露了标头,Ktor 也能够看到它,并且我能够根据需要存储和检索它。
我最终的 Ktor 代码只有:

middleware

© www.soinside.com 2019 - 2024. All rights reserved.