Oauth2 授权路由在 Ktor 中不起作用
Posted
技术标签:
【中文标题】Oauth2 授权路由在 Ktor 中不起作用【英文标题】:Oauth2 authorised routes not working in Ktor 【发布时间】:2021-06-21 01:03:50 【问题描述】:我的目标是获取 GitHub Oauth 令牌以允许访问 GitHub 数据并提供对 Web 应用程序中其他 Ktor 路由的访问控制。 我将 Ktor 示例简化为仅使用 GitHub,并且工作正常并从 GitHub 获取令牌。 但是,从不调用身份验证块中的其他路由。例如,/github/repos 被识别为路由(没有 404),但会通过 GitHub 重新进行身份验证并显示“成功登录”页面,而不是“从 GitHib 获取并显示 repos 信息”。我确信我缺少一些基本的东西,但我很感激地得到了任何帮助。 谢谢,马丁
import io.ktor.application.*
import io.ktor.auth.*
import io.ktor.client.*
import io.ktor.client.engine.apache.*
import io.ktor.html.*
import io.ktor.locations.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import kotlinx.html.*
import java.util.concurrent.TimeUnit
val githubProvider = OAuthServerSettings.OAuth2ServerSettings(
name = "github",
authorizeUrl = "https://github.com/login/oauth/authorize",
accessTokenUrl = "https://github.com/login/oauth/access_token",
clientId = "**client-id**",
clientSecret = "**client-secret**",
defaultScopes = listOf("repo", "user")
)
@Location("/home") class home
@Location("/github/login") class gitHubLogin
@Location("/github/repos") class gitHubRepos
@Location("/github/user") class gitHubUser
@KtorExperimentalLocationsAPI
fun main(args: Array<String>)
embeddedServer(Netty, port=8081)
module()
.start()
@KtorExperimentalLocationsAPI
fun Application.mainModule()
install(Authentication)
oauth("gitHubOAuth")
client = HttpClient(Apache)
providerLookup = githubProvider
urlProvider = url(gitHubLogin())
install(Locations)
install(Routing)
routing
get<home>
call.respondHtml
head
title +"index page"
body
h1
+"Try to login"
p
a(href = locations.href(gitHubLogin()))
+"Login"
authenticate("gitHubOAuth")
location<gitHubLogin>()
param("error")
handle
call.loginFailedPage(call.parameters.getAll("error").orEmpty())
handle
val principal = call.authentication.principal<OAuthAccessTokenResponse.OAuth2>()
if (principal != null)
call.loggedInSuccessResponse(principal)
else
call.loginPage()
get<gitHubUser>
call.respondHtml
body
p +"Get and display user info from GitHib"
get<gitHubRepos>
call.respondHtml
body
p +"Get and display repos info from GitHib"
@KtorExperimentalLocationsAPI
private suspend fun ApplicationCall.loginPage()
respondHtml
head
title +"Login with"
body
h1
+"Login with:"
p
a(href = application.locations.href(gitHubLogin()))
+"GitHub"
private suspend fun ApplicationCall.loginFailedPage(errors: List<String>)
respondHtml
head
title +"Login with"
body
h1
+"Login error"
for (e in errors)
p
+e
@KtorExperimentalLocationsAPI
private suspend fun ApplicationCall.loggedInSuccessResponse(callback: OAuthAccessTokenResponse?)
respondHtml
head
title +"Logged in"
body
h1
+"You are logged in"
p
+"Your token is $callback"
ul
li
a(href = locations.href(gitHubUser())) +"User"
li
a(href = locations.href(gitHubRepos())) +"Repos"
【问题讨论】:
【参考方案1】:每个客户端对任何受保护(authenticate
块下)路由的请求都会重复 OAuth 过程。您可以使用不受限制的路由来提供对需要令牌的资源的访问。在这些路由的处理程序中,您可以检查客户端是否成功通过身份验证。如果是,那么您可以从会话或与会话关联的令牌存储中获取令牌,并使用它从资源服务器获取数据;如果不是,则将客户端重定向到登录端点或显示错误消息。要使其正常工作,您可以使用 Sessions 来保留有关成功身份验证的知识。
下面是一个将令牌直接存储在会话中的示例。
配置Sessions
:
data class LoginSession(val token: String)
// ...
install(Sessions)
cookie<LoginSession>("LOGIN_SESSION")
在回调 URL 路由的处理程序中保存会话:
get("callback")
val principal = call.authentication.principal<OAuthAccessTokenResponse.OAuth2>()
if (principal != null)
call.sessions.set(LoginSession(token = principal.accessToken))
使用非限制路由提供对某些资源的访问:
get("repos")
val repos = call.withAuth session ->
HttpClient(Apache).get<String>("https://api.github.com/user/repos")
header("Authorization", "token $session.token")
call.respondText repos
ApplicationCall.withAuth
方法只是检查会话是否存在的助手:
suspend fun <T: Any> ApplicationCall.withAuth(block: suspend (session: LoginSession) -> T): T
val session = sessions.get<LoginSession>()
if (session != null)
return block(session)
respondRedirect("/login")
throw Exception("Not authenticated")
【讨论】:
非常感谢您的回答完全有道理。以上是关于Oauth2 授权路由在 Ktor 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot OAuth2 CORS 在版本 2.2.1 中不起作用
身份验证在spring boot 1.5.2和Oauth2中不起作用