具有 keycloak 的 ktor 中相同 oauth 设置上的多个 urlProviders

Posted

技术标签:

【中文标题】具有 keycloak 的 ktor 中相同 oauth 设置上的多个 urlProviders【英文标题】:Multiple urlProviders on the same oauth setting in ktor with keycloak 【发布时间】:2021-06-10 13:37:11 【问题描述】:

我正在制作一个使用 keycloak 作为身份验证的 ktor Web 应用程序。

val keycloakProvider = OAuthServerSettings.OAuth2ServerSettings(
    name = CLIENT_NAME,
    authorizeUrl = KEYCLOAK_AUTH,
    accessTokenUrl = KEYCLOAK_TOKEN,
    clientId = CLIENT_ID,
    clientSecret = CLIENT_SECRET,
    accessTokenRequiresBasicAuth = false,
    requestMethod = HttpMethod.Post, // must POST to token endpoint
    defaultScopes = listOf("roles")
)

我想要保护多个端点,但重定向 URI 只能设置为一个 URL,在下面的示例中为 /login/oauth/secret

    install(Authentication)
    
        oauth("secretOAuth") 
            client = HttpClient(Apache)
            providerLookup =  keycloakProvider 
            urlProvider =  "/secret" 
        
        oauth("keycloakOAuth") 
            client = HttpClient(Apache)
            providerLookup =  keycloakProvider 
            urlProvider =  "/login/oauth" 
        
    

像上面的示例那样创建多个这样的身份验证路径是否有意义,还是不好的做法? /login/oauth/secret 指向以下路由:

    authenticate(keycloakOAuth) 
        get("/login/oauth") 
            val principal = call.authentication.principal<OAuthAccessTokenResponse.OAuth2>()
                ?: throw Exception("No principal was given")

            createSession(principal)
            call.respondRedirect("/")
        
    

    authenticate(secretOAuth)
        get("/secret")
        
            val principal = call.authentication.principal<OAuthAccessTokenResponse.OAuth2>()
                ?: throw Exception("No principal was given")
            createSession(principal)
            call.respondhtml 
                body
                    h1
                            +"You accessed secure page!"
                    
                
            
        
    

功能方面,它可以工作,当用户未登录时,它会通过登录窗口提示他们,否则他们会看到秘密/他们的会话被创建,但我不确定这是否是正确的做法它。真的没有办法根据访问的URI更改urlProvider吗?因为那样我将不得不为每个受保护的端点进行身份验证,这可能有点太多了。

【问题讨论】:

【参考方案1】:

在您的场景中,为同一个提供者配置多个身份验证配置是多余的,因为客户端可以获取任何访问令牌。我建议使用authenticate 块来获取访问令牌并将其保存在某处。您可以对“秘密”资源使用通常的路由,您可以在其中检查具有访问令牌的用户。

routing 
    authenticate("keycloakOAuth") 
        get("/login") 
            // The endpoint for user login
        

        get("/callback") 
            val principal = call.authentication.principal<OAuthAccessTokenResponse.OAuth2>()

            if (principal != null) 
                // Save access token (principal.accessToken) for further use
             else 
                // Something went wrong
            
        
    
    
    get("/secret") 
        if (!hasToken()) 
            call.respondRedirect("/login")
        
    

【讨论】:

好的,这解决了我一半的问题。我想要的是 keycloak 在登录后将我重定向到 /secret 端点。这在 ktor 中如何工作,如何动态传递任何秘密端点的重定向?我尝试在安装块中定义多个 oauth 的原因是我没有找到任何其他方式在身份验证后将用户重定向到该特定端点。 您可以将用户重定向到/callback 处理程序中的任何位置。 嗯,好的,感谢您的快速响应。所以我会用这行call.respondRedirect("/")重定向用户。但是我不确定如何在回调处理程序中获取原始 uri,例如 /secret 。它可以在调用对象中访问吗?因为我似乎找不到它。 很遗憾,我找不到获取原始 URI 的方法。您可能可以将此信息保存在客户端的会话 ktor.io/docs/sessions.html 中,稍后将其用于重定向。

以上是关于具有 keycloak 的 ktor 中相同 oauth 设置上的多个 urlProviders的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在不使用其 UI 的情况下使用 KeyCloak 身份验证?

带有 https 的负载均衡器后面的 Keycloak Docker 失败

为啥 Keycloak 会不断重新部署相同的 .jar 文件?

Ktor 客户端的 JsonFeature 未解决

在单独的线程中初始化 Ktor 可以吗?

在 Ktor 0.9.0 servlet 中控制 cookie 生命周期