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

bbuxkriu  于 12个月前  发布在  Ruby
关注(0)|答案(1)|浏览(144)

我对Rails和KotlinJs相当熟悉,但我是做auth的新手,我很困惑。
我设置了Rails Devise,并按照tutorials在线添加了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应该通过Credentials: Include保存在JS FetchApi中的浏览器中,但我不知道如何在Ktor中做到这一点。有人建议通过主体发送令牌,即使我几乎可以肯定这是错误的解决方案,如果我知道怎么做的话,我愿意试试。

wz1wpwve

wz1wpwve1#

经过长时间的工作,我意识到我的错误是在rails后端:我已经按照指令暴露了header 'Authorization',但我在错误的函数中暴露了它,'Cors' initializer,而不是我应该暴露的middleware。一旦我正确暴露了header,Ktor也能够看到它,我就能够存储它并根据需要检索它。
我的最终Ktor代码只有:

val BACKEND = Url("http://localhost:3000/")
const val AUTHORIZATION = "Authorization"

val client by lazy {
    HttpClient(Js) {
        install(ContentNegotiation) { json() }
    }
}

suspend fun login(username: String, password: String) {
    val userData = User(user = UserData(username = username, password = password))

    val response = client.post("$BACKEND/users/sign_in"){
        contentType(ContentType.Application.Json)
        setBody(userData)
    }

    val token = response.headers[AUTHORIZATION]
    if (response.status == HttpStatusCode.OK && token != null) {
        localStorage.setItem(AUTHORIZATION, token)
        mainPage()
    }
}

字符串

相关问题