Ktor 中的表单身份验证

2024-01-01

我是新来的Kotlin and Ktor试图查看身份验证部分,所以我得到了以下代码。

路由“/”和“/bye”工作正常,但路由“login”给出空白页面!

package blog

import kotlinx.html.*
import kotlinx.html.stream.*    // for createHTML
import org.jetbrains.ktor.application.*
import org.jetbrains.ktor.auth.*
import org.jetbrains.ktor.features.*
import org.jetbrains.ktor.http.*
import org.jetbrains.ktor.response.*
import org.jetbrains.ktor.routing.*

import org.jetbrains.ktor.request.*   // for request.uri

import org.jetbrains.ktor.html.*
import org.jetbrains.ktor.pipeline.*

import org.jetbrains.ktor.host.*   // for embededServer
import org.jetbrains.ktor.netty.*  // for Netty

fun main(args: Array<String>) {
    embeddedServer(Netty, 8080, watchPaths = listOf("BlogAppKt"), module = Application::module).start()
}

fun Application.module() {
    install(DefaultHeaders)
    install(CallLogging)

    intercept(ApplicationCallPipeline.Call) { 
        if (call.request.uri == "/hi")
            call.respondText("Test String")
    }

    install(Routing) {
        get("/") {
            call.respondText("""Hello, world!<br><a href="/bye">Say bye?</a>""", ContentType.Text.Html)
        }
        get("/bye") {
            call.respondText("""Good bye! <br><a href="/login">Login?</a> """, ContentType.Text.Html)
        }
        route("/login") {
            authentication {
                formAuthentication { up: UserPasswordCredential ->
                    when {
                        up.password == "ppp" -> UserIdPrincipal(up.name)
                        else -> null
                    }
                }
            }

            handle {
                val principal = call.authentication.principal<UserIdPrincipal>()
                if (principal != null) {
                    call.respondText("Hello, ${principal.name}")
                } else {
                        val html = createHTML().html {
                        body {
                            form(action = "/login", encType = FormEncType.applicationXWwwFormUrlEncoded, method = FormMethod.post) {
                                p {
                                    +"user:"
                                    textInput(name = "user") {
                                        value = principal?.name ?: ""
                                    }
                                }

                                p {
                                    +"password:"
                                    passwordInput(name = "pass")
                                }

                                p {
                                    submitInput() { value = "Login" }
                                }
                            }
                        }
                    }
                    call.respondText(html, ContentType.Text.Html)
                }
            }
        }
    }
}

当我禁用下面的身份验证部分时,路由“/login”显示所需的形式,这意味着错误很可能出现在这部分或调用它的方式中?我猜。

            authentication {
                formAuthentication { up: UserPasswordCredential ->
                    when {
                        up.password == "ppp" -> UserIdPrincipal(up.name)
                        else -> null
                    }
                }
            }

您得到的不仅仅是一个空白页面,您还会得到一个 HTTP 状态代码401 (UNAUTHORIZED)。那是因为formAuthentication有四个参数,其中三个具有默认值。您只实现了最后一个(validate,无默认值):

userParamName: String = "user",
passwordParamName: String = "password",
challenge: FormAuthChallenge = FormAuthChallenge.Unauthorized,
validate: (UserPasswordCredential) -> Principal?

每当你到达/login如果没有正确的凭据,您将获得默认的路由challenge,即FormAuthChallenge.Unauthorized,这是一个401回复。

而不是使用默认值challenge,你可以使用FormAuthChallenge.Redirect。一个需要两条路线的简短示例:

get("/login") {
    val html = """
            <form action="/authenticate" enctype="..."
            REST OF YOUR LOGIN FORM
            </form>
            """
    call.respondText(html, ContentType.Text.Html)
}

route("/authenticate") {
    authentication {
        formAuthentication(challenge = FormAuthChallenge.Redirect({ _, _ -> "/login" })) {
            credential: UserPasswordCredential ->
            when {
                credential.password == "secret" -> UserIdPrincipal(credential.name)
                else -> null
            }
        }
    }

    handle {
        val principal = call.authentication.principal<UserIdPrincipal>()
        val html = "Hello, ${principal?.name}"
        call.respondText(html, ContentType.Text.Html)
    }
}

UPDATE

如果上述方法效果不佳,请定义userid-parameter and password-parameter显然,正如它们出现在form这样做的POST, 如下:

        authentication {
            formAuthentication("user", "pass",
                    challenge = FormAuthChallenge.Redirect({ _, _ -> "/login" })){
                credential: UserPasswordCredential ->
                when {
                credential.password == "secret" -> UserIdPrincipal(credential.name)
                else -> null
                }
            }
        }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Ktor 中的表单身份验证 的相关文章

随机推荐

  • 如何在 Rails 中自动将所有链接设置为 nofollow

    我知道我可以通过 rel gt nofollow to link to但有没有一种方法可以默认设置 这样我就不必在每个中进行更改link to tag 在您的应用程序助手中 您可以覆盖link to方法并替换为您自己的 def link t
  • C switch 语句的汇编 - 它是如何工作的?

    我正在读一本关于汇编 switch 语句的书 当输入 n 为 case 100 102 103 104 106 时 代码有 case branch 它通过从 n 中减去 100 来简化跳转表 然后如果结果是上面的6 进入L2中的默认情况 否
  • mp3 文件的时间长度

    确定给定 mp3 文件的长度 以秒为单位 的最简单方法是什么 不使用外部库 高度赞赏Python源代码 您可以使用pymad http spacepants org src pymad 它是一个外部库 但不要陷入 Not Invented
  • Scala 中的地图内的地图

    我有这个代码 val total ListMap String HashMap Int val hm1 new HashMap Int String val hm2 new HashMap Int Int insert values in
  • 在 R 中查找矩阵的相邻元素

    编辑 非常感谢以下用户的巨大贡献以及 Gregor 的基准测试 假设我有一个充满整数值的矩阵 如下所示 mat lt matrix 1 100 10 10 我可以像这样创建每个元素的 x y 坐标列表 addresses lt expand
  • Flutter如何访问FCM backgroundHandler静态方法中的provider.of(context)?

    我已成功设置后台通知并使用邮递员对其进行了测试 一切都很好 现在我需要在我的backgroundHandler 中访问Provider of context 它必须是没有上下文的静态方法 我需要做的就是根据后台通知中的数据执行操作 这是我初
  • 在 Ubuntu 上通过 Python 使用 Access 数据库 (.mdb) [重复]

    这个问题在这里已经有答案了 我正在尝试使用 pyodbc 访问 Ubuntu 上的 mdb 到目前为止我的进展基于此链接 查询使 MS Access 崩溃 https stackoverflow com questions 3064830
  • 在 Ionic 应用程序中全屏横向播放视频

    我在播放视频横向全屏模式时遇到问题 请帮助我以横向全屏模式显示视频 我使用以下代码在 Ionic 中查看模板
  • 绘制 Matplotlib 等高线图的轴线或原点

    我想画画x 0 and y 0等高线图中的轴 使用白色 如果这太麻烦了 我想要一个白点来表示原点在哪里 我的等高线图如下所示 下面给出了创建它的代码 xvec linspace 5 5 100 X Y meshgrid xvec xvec
  • 如何使用 OCMock 验证某个方法从未被调用?

    在我的日常工作中 我被宠坏了莫基托的never 确认 http mockito googlecode com svn tags latest javadoc org mockito Mockito html never 这可以确认模拟方法从
  • NSArray:lastObject 返回一个自动释放的对象吗?

    我正在开发一个 iPhone 项目 我想从 NSMutableArray 中检索一个对象 从数组中删除该对象 然后在以后使用它 代码看起来像这样 NSMutableArray array fill the array NSObject ob
  • 使用 STL 在 C++ 中处理大于 2 GB 的文件

    我正在进行二进制文件处理 在我的算法中我想知道实际类型pos type and off type 例如计算文件大小或查找给定位置时 tellg and seekg 当计算文件的大小时我只是static cast the pos type t
  • 根据构建配置嵌入不同的框架

    我有 4 种构建配置 Debug Release 白标调试 白标发布 Debug and Release应该链接并嵌入我的自定义LightTheme framework而不是WhiteLabelTheme framework WhiteLa
  • 在批处理脚本中查询注册表项

    我使用以下代码来获取启动时运行的程序列表 并将它们记录到文件中 for f skip 2 tokens 1 2 A in REG QUERY HKCU SOFTWARE Wow6432Node Microsoft Windows Curre
  • 未记录的支持 Date.parse 格式?

    MDN s 的文档Date parse https developer mozilla org en JavaScript Reference Global Objects Date parse says 参数 dateString一个字符
  • 如何同时在2个不同的symfony2防火墙上进行身份验证?

    我有一个包含 2 个区域的 Symfony 应用程序 一个区域用于客户端从网页访问 另一个区域用于来自 AJAX 和 Web 服务的 API 调用 每个区域都由自己的防火墙保护 WEB 界面通过登录表单和 API 进行身份验证http ba
  • 如何在视图集中添加自定义权限

    创建模块时 如何在 django Rest Framework 的视图集中添加除默认权限之外的自定义权限 我有权限 fix an appointment 在下面的视图集中 如何包含此权限 拥有此权限的人只能进行创作 我的views py文件
  • 使用 Python 请求提取 href URL

    我想使用 python 中的 requests 包从 xpath 中提取 URL 我可以获取文本 但我尝试没有给出 URL 有人可以帮忙吗 ipdb gt webpage xpath xpath url text Text of the U
  • 在 tkinter 中显示网格布局单元

    有没有trick使用它时显示网格布局单元格 或单元格的边框 以便直观地了解幕后发生的情况 我已经搜索了一点 但还没有找到任何东西 如果您为包含框架指定颜色 并使用选项在单元格之间放置填充 则背景将通过间隙渗透 这只适用于有小部件的地方 如果
  • Ktor 中的表单身份验证

    我是新来的Kotlin and Ktor试图查看身份验证部分 所以我得到了以下代码 路由 和 bye 工作正常 但路由 login 给出空白页面 package blog import kotlinx html import kotlinx