Ktor 中如何动态选择使用哪种认证方式?

How to dynamically choose which authentication method is used in Ktor?

我在我的应用程序中实现了 google sign-in:

fun Application.module(testing: Boolean = false) {
  install(CallLogging)

  install(ContentNegotiation) {
    gson {
      setPrettyPrinting()
    }
  }

  val jwtIssuer = environment.config.property("jwt.domain").getString()
  val jwtAudience = environment.config.property("jwt.audience").getString()
  val jwtRealm = environment.config.property("jwt.realm").getString()

  val jwkProvider = JwkProviderBuilder(URL("https://www.googleapis.com/oauth2/v3/certs"))
    .cached(10, 24, TimeUnit.HOURS)
    .rateLimited(10, 1, TimeUnit.MINUTES)
    .build()

  install(Authentication) {
    jwt {
      verifier(jwkProvider) {
        withIssuer(jwtIssuer)
        withAudience(jwtAudience)
      }
      realm = jwtRealm
      validate { credentials ->
        if (credentials.payload.audience.contains(jwtAudience))
          JWTPrincipal(credentials.payload)
        else
          null
      }
    }
  }

  routing {
    authenticate {
      post("/token-sign-in") {
        val payload = call.principal<JWTPrincipal>()?.payload ?: error("JWTPrincipal not found")

        call.respond(
          UserWire(
            id = payload.subject,
            email = payload.getClaim("email").asString(),
            name = payload.getClaim("name").asString(),
            profilePictureUrl = payload.getClaim("picture").asString()
          )
        )
      }
    }
  }
}

我想在用户每次访问其中一条路由时对用户进行身份验证,但我希望同时选择 google 和 firebase-auth 登录。问题是他们需要不同的方法来检查给定令牌的真实性,因此我需要两种身份验证方法。

我想在调用的 header 中包含一个 "AuthenticationProvider: "Google|Firebase"" ,我会根据它的值来决定应该调用哪种身份验证方法.

所以像这样:

fun Application.module(testing: Boolean = false) {
  install(Authentication) {
    jwt("google") {
      // verify google sign in token
    }
    jwt("firebase") {
      // verify firebase token
    }
    firebaseOrGoogle("firebaseOrGoogle") {
      // check header value for auth provider
      // verify token with either "firebase" or "google" auth methods
    }
  }

  routing {
    authenticate("firebaseOrGoogle") {
      post("/token-sign-in") {
        // ...
      }

      get("/transactions") {
        // ...
      }
    }
  }
}

这可能吗? 如果可行,请提供一些代码,说明如何动态决定应调用哪种身份验证方法?

作为替代解决方案,您可以配置身份验证功能以尝试通过这两种方法证明用户的身份。第一次成功的检查获胜。为此,只需将这两个配置名称传递给 authenticate 方法:

routing {
    authenticate("google", "firebase") {
        post("/token-sign-in") {
            // ...
        }

        get("/transactions") {
            // ...
        }
    }
}

参数的顺序决定了首先进行的检查。