Firebase 身份验证不适用于 AppEngine 上的 Ktor 应用程序

标签 firebase google-app-engine google-cloud-firestore ktor

问题

根据 Ktor tutorial Ktor Kotlin 应用程序部署到 AppEngine 时,Firestore 服务器身份验证不起作用,因此数据未写入指定的 Firestore 数据库。

当应用程序直接在 IntelliJ IDE 中运行时,以及通过 gradle appengineRun 命令使用 ktor 的实现运行时,数据都按预期写入 Firestore。

有两组 AppEngine/Firebase 项目用于暂存环境和生产环境。在使用 gradle appengineDeploy 命令部署之前,正确的 SDK 配置已通过命令 gcloud config configurations list. 激活和验证

enter image description here

奇怪的是,使用这些策略部署的一些应用程序确实写入了 Firestore,但是在再次部署应用程序时,Firestore 没有显示正在写入新数据。

执行

Ktor 设置

我有标准的 ktor 所需文件。我还有一个来自旧实现的旧 MANIFEST.MF 文件。这会导致问题吗?

src/main/resources/application.conf

ktor {
  application {
  modules = [ Initialization.main ]
  }
}

src/main/resources/webapp/WEB-INF/

appengine-web.xml
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <threadsafe>true</threadsafe>
    <runtime>java8</runtime>
</appengine-web-app>

网页.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<servlet>
    <display-name>KtorServlet</display-name>
    <servlet-name>KtorServlet</servlet-name>
    <servlet-class>io.ktor.server.servlet.ServletApplicationEngine</servlet-class>
    <!-- path to application.conf file, required -->
    <init-param>
        <param-name>io.ktor.config</param-name>
        <param-value>application.conf</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>KtorServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

logging.properties
.level = INFO
src/main/META-INF/MANIFEST>MF
Manifest-Version: 1.0
Main-Class: Initialization

依赖关系

对于下面概述的身份验证策略 #1-3 使用 Firebase 管理库:compile 'com.google.firebase:firebase-admin:6.5.0'
对于身份验证策略 #4 ,使用 Google Cloud Firestore 库:compile 'com.google.cloud:google-cloud-firestore:0.58.0-beta'
build.gradle
group 'coinverse'
version '1.0-SNAPSHOT'

buildscript {
    ext.kotlin_version = '1.2.61'
    ext.junitJupiterVersion  = '5.0.3'
    ext.ktor_version = '0.9.4'
    ext.appengine_version = '1.9.60'
    ext.appengine_plugin_version = '1.3.4'

repositories {
    mavenCentral()
    jcenter()
}
dependencies {
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.3'
    classpath "com.google.cloud.tools:appengine-gradle-plugin:$appengine_plugin_version"
    }
}

apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'war'
apply plugin: 'com.google.cloud.tools.appengine'

sourceSets {
    main.kotlin.srcDirs = [ 'src/main/kotlin' ]
}

sourceCompatibility = 1.8

repositories {
mavenCentral()
jcenter()
maven { url "https://kotlin.bintray.com/ktor" }
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    testCompile group: 'junit', name: 'junit', version: '4.12'
    testCompile("org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}")
        testRuntime("org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}")
        testCompile("org.assertj:assertj-core:3.10.0")
        testCompileOnly('org.apiguardian:apiguardian-api:1.0.0')
        compile 'com.squareup.retrofit2:retrofit:2.3.0'
        compile 'com.squareup.retrofit2:converter-gson:2.3.0'
        compile 'com.squareup.retrofit2:adapter-rxjava:2.3.0'
        compile 'io.reactivex.rxjava2:rxjava:2.2.0'
        compile 'com.google.cloud:google-cloud-firestore:0.58.0-beta'
        // Or compile 'com.google.cloud:google-cloud-firestore:0.58.0-beta'
        compile 'com.google.firebase:firebase-admin:6.5.0'
        compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
        compile "io.ktor:ktor-server-servlet:$ktor_version"
        compile "io.ktor:ktor-html-builder:$ktor_version"
        providedCompile "com.google.appengine:appengine:$appengine_version"
}

kotlin.experimental.coroutines = 'enable'

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

task run(dependsOn: appengineRun)

appengine {
    deploy {
        version = 'price-staging-1021653pm'
        stopPreviousVersion = false
    }
}

初始化 Firebase 策略

1. Initialize on Google Cloud Platform

这种方法很有前途,因为凭证是自动管理的。
// Use the application default credentials
GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
FirebaseOptions options = new FirebaseOptions.Builder()
    .setCredentials(credentials)
    .setProjectId(projectId)
    .build();
FirebaseApp.initializeApp(options);

Firestore db = FirestoreClient.getFirestore();

2. Initialize on your own server

我已经在 GCPs IAM & admin > Service accounts 中确认 key ID 与用于身份验证的 Json 对象匹配。

我在另一个部署到 AppEngine 的 Firestore 连接应用程序中成功使用了这个策略。工作应用程序构建为 .Jar 并直接部署到 AppEngine 而不使用 ktor ,而是使用 here 概述的步骤。
// Use a service account
InputStream serviceAccount = new FileInputStream("path/to/serviceAccount.json");
GoogleCredentials credentials = GoogleCredentials.fromStream(serviceAccount);
FirebaseOptions options = new FirebaseOptions.Builder()
    .setCredentials(credentials)
    .build();
FirebaseApp.initializeApp(options);

Firestore db = FirestoreClient.getFirestore();

在我的工作 .Jar 构建的应用程序中,我以编程方式传入 Json 对象以避免找不到文件的问题。我为这个 ktor 应用程序尝试了相同的编程实现。它与 gradle appengineRun 一起工作,但在部署时不起作用。
val credentials = GoogleCredentials.fromStream(Gson().toJson(FirebaseCredentials(
            "service_account",
            "project-name",
            "asdfghjkl",
            "keyStringHere",
            "firebase-adminsdk-dhr30@project-name.iam.gserviceaccount.com",
            "1234567890",
            "https://accounts.google.com/o/oauth2/auth",
            "https://oauth2.googleapis.com/token",
            "https://www.googleapis.com/oauth2/v1/certs",
           "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-dhr30%40project-name-staging.iam.gserviceaccount.com"
    )).byteInputStream())
    val options = FirebaseOptions.Builder()
            .setCredentials(credentials)
            .setDatabaseUrl("https://project-name-staging.firebaseio.com")
            .build()

    FirebaseApp.initializeApp(options)

3. 在您自己的服务器上初始化(Firebase 控制台设置)

#2 之间的唯一区别是此设置添加了 .setDatabaseUrl("https://yourProjectName.firebaseio.com")

enter image description here

4. Initialize cloud Firestore
FirestoreOptions firestoreOptions =
FirestoreOptions.getDefaultInstance().toBuilder()
    .setProjectId(projectId)
    .build();
Firestore db = firestoreOptions.getService();

访问 Firestore 对象

对于 #1-3 ,Firebase 应用立即在应用的 main() 方法中初始化。然后,从对象访问 Firestore 对象。

FirebaseClient.Kt
object FirebaseClient {
    val firestore: Firestore
    init {
        firestore = FirestoreClient.getFirestore()
    }
}

对于 #4 ,Firestore 对象在 Kotlin 对象的 init{...} 中创建并作为值存储在对象中。

FirebaseClient.Kt
object FirebaseClient {
    val firestore: Firestore

    init {
        val firestoreOptions = FirestoreOptions.getDefaultInstance().toBuilder()
            .setTimestampsInSnapshotsEnabled(true)
            .setProjectId("project-name")
            .build()
        firestore = firestoreOptions.service
    }
}

写入 Firestore
FirebaseClient.firestore.collection(someCollection).document(someDocument).collection(anotherCollection).add(someObject)

最佳答案

在对不同项目使用 Firebase 身份验证后,我发现这不是 Firebase 身份验证的问题,而是应用程序的 问题。主 方法。因此,当部署到 AppEngine 时,上述 Firebase 身份验证的各种实现将按预期工作。

解决方案

我期待应用程序的 应用程序部署到 AppEngine 后运行的方法,类似于在 IntelliJ 中运行时调用应用程序的 main 方法的方式。然而我意识到仅在调用应用程序的托管路由后才调用。

即:https://[yourProjectName].appspot.com
我创建了一个新的 StackOverflow 帖子以确定 how to run a Ktor app's main method automatically once deployed .

关于Firebase 身份验证不适用于 AppEngine 上的 Ktor 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52922552/

相关文章:

android - 为什么当应用程序处于后台时声音不响(Android应用程序中的Firebase推送通知)?

python - GAE 中的多对多关系。查询失败

python - 如何获取数据存储名称/id 列值

firebase - 如何将图像 URL(来自 Firebase 存储)存储到 Firestore [Flutter]

firebase - Firestore 安全规则。用户可以知道别人的 UID 吗?

java - 与谷歌即时游戏和 com.google.gms.google-services 插件冲突

Firebase 存储规则,如何写入特定文件夹?

firebase - Flutter:未处理的异常:错误状态:DocumentSnapshotPlatform中不存在该字段

android - Flutter/cloud-firestore "Task is already complete"异常

google-app-engine - 如何使用 Python 后端通过 HTTPS POST 接收 id token ?