英文:
Trying to set up OAuth with Ktor, providerLookup problems
问题
我正在尝试为Kotlin Ktor设置OAuth。我尝试遵循文档,但在第2步的配置部分上遇到问题。当我的程序运行时:
call.request.queryParameters["redirectUrl"]!!
我得到一个空指针异常。在调试器模式下运行程序时,我可以看到call/request/queryParameters
不为空。因此,应该是"redirectUrl"
没有"工作"。
我尝试搜索这行代码应该做什么,但无法在任何地方找到解释。我只能在这个文档中找到它的使用。我假设它应该获取一些重定向URL,但我不知道应该从哪里获取。
我该怎么解决空指针异常?
如果有帮助的话,这是我的类:
package com.example.plugins
import io.ktor.server.auth.*
import io.ktor.client.*
import io.ktor.client.engine.apache.*
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.sessions.*
import io.ktor.server.response.*
import io.ktor.server.application.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.routing.*
fun Application.configureSecurity() {
val redirects = mutableMapOf<String, String>()
authentication {
oauth("auth-oauth-google") {
urlProvider = { "http://localhost:8086/callback" }
providerLookup = {
OAuthServerSettings.OAuth2ServerSettings(
name = "google",
authorizeUrl = "https://accounts.google.com/o/oauth2/auth",
accessTokenUrl = "https://accounts.google.com/o/oauth2/token",
requestMethod = HttpMethod.Post,
clientId = System.getenv("GOOGLE_CLIENT_ID"),
clientSecret = System.getenv("GOOGLE_CLIENT_SECRET"),
defaultScopes = listOf("https://www.googleapis.com/auth/userinfo.profile"),
extraAuthParameters = listOf("access_type" to "offline"),
onStateCreated = { call, state ->
redirects[state] = call.request.queryParameters["redirectUrl"]!!
}
)
}
client = HttpClient(Apache)
}
}
data class MySession(val count: Int = 0)
install(Sessions) {
cookie<MySession>("MY_SESSION") {
cookie.extensions["SameSite"] = "lax"
cookie.maxAgeInSeconds = 120
cookie.path = "/testing"
}
cookie<UserSession>("USER_SESSION") {
cookie.extensions["SameSite"] = "lax"
cookie.maxAgeInSeconds = 120
cookie.path = "/testingss"
}
}
routing {
authenticate("auth-oauth-google") {
get("login") {
call.respondRedirect("/callback")
}
get("/callback") {
val principal: OAuthAccessTokenResponse.OAuth2? = call.principal()
call.sessions.set(UserSession(principal!!.state!!, principal.accessToken))
val redirect = redirects[principal.state!!]
call.respondRedirect(redirect!!)
}
}
get("/session/increment") {
val session = call.sessions.get<MySession>() ?: MySession()
call.sessions.set(session.copy(count = session.count + 1))
call.respondText("Counter is ${session.count}. Refresh to increment.")
}
}
}
英文:
So Im trying to set up OAuth for Kotlin, Ktor. Im trying to follow the documentation
on but I get stuck on the config part on step 2. When my program runs:
call.request.queryParameters["redirectUrl"]!!
I get a null point exeption. When running the program in a debugger mode I can see that call/request/queryParameters is not null. So it should be the "redirectUrl" that is not "working".
I have tried to search for what the line is suppose to do but I cant find any explanation of it anywhere. I can only finds its use in this documentation. I assume it is suppose to get some redirecting URLs but I have no clue from where.
What can I do to solve my null point exeption?
Here is my class if it helps
package com.example.plugins
import io.ktor.server.auth.*
import io.ktor.client.*
import io.ktor.client.engine.apache.*
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.sessions.*
import io.ktor.server.response.*
import io.ktor.server.application.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.routing.*
fun Application.configureSecurity() {
val redirects = mutableMapOf<String, String>()
authentication {
oauth("auth-oauth-google") {
urlProvider = { "http://localhost:8086/callback" }
providerLookup = {
OAuthServerSettings.OAuth2ServerSettings(
name = "google",
authorizeUrl = "https://accounts.google.com/o/oauth2/auth",
accessTokenUrl = "https://accounts.google.com/o/oauth2/token",
requestMethod = HttpMethod.Post,
clientId = System.getenv("GOOGLE_CLIENT_ID"),
clientSecret = System.getenv("GOOGLE_CLIENT_SECRET"),
defaultScopes = listOf("https://www.googleapis.com/auth/userinfo.profile"),
extraAuthParameters = listOf("access_type" to "offline"),
onStateCreated = { call, state ->
redirects[state] = call.request.queryParameters["redirectUrl"]!!
}
)
}
client = HttpClient(Apache)
}
}
data class MySession(val count: Int = 0)
install(Sessions) {
cookie<MySession>("MY_SESSION") {
cookie.extensions["SameSite"] = "lax"
cookie.maxAgeInSeconds = 120
cookie.path = "/testing"
}
cookie<UserSession>("USER_SESSION") {
cookie.extensions["SameSite"] = "lax"
cookie.maxAgeInSeconds = 120
cookie.path = "/testingss"
}
}
routing {
authenticate("auth-oauth-google") {
get("login") {
call.respondRedirect("/callback")
}
get("/callback") {
val principal: OAuthAccessTokenResponse.OAuth2? = call.principal()
call.sessions.set(UserSession(principal!!.state!!, principal.accessToken))
val redirect = redirects[principal.state!!]
call.respondRedirect(redirect!!)
}
}
get("/session/increment") {
val session = call.sessions.get<MySession>() ?: MySession()
call.sessions.set(session.copy(count = session.count + 1))
call.respondText("Counter is ${session.count}. Refresh to increment.")
}
}
}
答案1
得分: 1
如果需要将客户端重定向到其来源URL,请在/login
端点添加查询参数redirectUrl
(实际名称无关紧要,但必须一致)。以下是工作流程的步骤:
- 客户端请求一个未受保护的端点。
- 如果会话不存在(客户端未经身份验证),服务器将以查询参数
redirectUrl
的形式重定向到/login
,其中包含请求的URL。 /login
端点触发OAuth2身份验证,创建state
时,将redirectUrl
保存到onStateCreated
块内的redirects
映射中。- OAuth2提供者将客户端重定向到回调URL,重定向将发生到先前保存的URL。
以下是一个示例:
get("/{path}") {
val userSession: UserSession? = call.sessions.get()
if (userSession != null) {
val userInfo: UserInfo = httpClient.get("https://www.googleapis.com/oauth2/v2/userinfo") {
headers {
append(HttpHeaders.Authorization, "Bearer ${userSession.token}")
}
}.body()
call.respondText("Hello, ${userInfo.name}!")
} else {
val redirectUrl = URLBuilder("http://0.0.0.0:8080/login").run {
parameters.append("redirectUrl", call.request.uri)
build()
}
call.respondRedirect(redirectUrl)
}
}
如有需要,您可以使用此示例代码来实现所描述的重定向逻辑。
英文:
If you need to redirect a client to the URL it came from, add the query parameter redirectUrl
(the actual name doesn't matter but has to be consistent) to the /login
endpoint. Here are the steps of the flow:
- Client requests an unprotected endpoint
- If the session is absent (the client is unauthenticated), the server responds with a redirect to
/login
with a query parameterredirectUrl
, which contains the requested URL. - The
/login
endpoint triggers OAuth2 authentication, and when astate
is created, theredirectUrl
is saved to theredirects
map inside theonStateCreated
block. - The client is redirected by the OAuth2 provider to the callback URL, where the redirect is happening to the previously saved URL.
Here is an example:
get("/{path}") {
val userSession: UserSession? = call.sessions.get()
if (userSession != null) {
val userInfo: UserInfo = httpClient.get("https://www.googleapis.com/oauth2/v2/userinfo") {
headers {
append(HttpHeaders.Authorization, "Bearer ${userSession.token}")
}
}.body()
call.respondText("Hello, ${userInfo.name}!")
} else {
val redirectUrl = URLBuilder("http://0.0.0.0:8080/login").run {
parameters.append("redirectUrl", call.request.uri)
build()
}
call.respondRedirect(redirectUrl)
}
}
答案2
得分: 1
我成功修复了它,只需将call.request.queryParameters["redirectUrl"]!!
替换为普通字符串,如"http://localhost:3000/home"
即可。
只要你要重定向的URL保持一致,它就能正常工作。
英文:
I was able to fix it by exchanging call.request.queryParameters["redirectUrl"]!!
with just a normal string, such as "http://localhost:3000/home"
.
Works as long as you only have the same url you are going to redirect to.
答案3
得分: 0
答案提供的内容未解决问题。在使用ktor oauth模型示例时出现了NullPointerException。
另外,在get("/{path}") {}
块中,当存在会话可用时,如何进行重定向?如果我尝试调用call.respondRedirect()
,它会再次进入get("/{path}") {}
块,这会导致无限循环。
英文:
The answer given is not addressing the problem. There is NullPointerException when the ktor oauth model example is used.
Also, in the get("/{path}") {} block, for the case when there is a existing session avilable, how do we redirect? If I try to call.respondRedirect(), it again lands into get("/{path}") {} block. This is infinite loop.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论