Firebase 身份验证不适用于 AppEngine 上的 Ktor 应用程序
Posted
技术标签:
【中文标题】Firebase 身份验证不适用于 AppEngine 上的 Ktor 应用程序【英文标题】:Firebase Auth Not Working With Ktor App On AppEngine 【发布时间】:2019-03-26 03:03:43 【问题描述】:问题
当根据Ktor tutorial 将 Ktor Kotlin 应用程序部署到 AppEngine 时,Firestore 服务器身份验证不起作用,因此数据不会写入指定的 Firestore 数据库。
当应用程序直接在 IntelliJ IDE 中运行以及通过 gradle appengineRun
命令使用 ktor 的实现运行时,数据都会按预期写入 Firestore。
staging 和 production 环境都有两组 AppEngine/Firebase 项目。在使用 gradle appengineDeploy
命令部署之前,正确的 SDK 配置已通过命令 gcloud config configurations list.
进行激活和验证
奇怪的是,使用这些策略部署的一些应用确实写入了 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>
web.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
我已在 GCP IAM 和管理员 > 服务帐户中确认密钥 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")
。
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)
【问题讨论】:
【参考方案1】:在对另一个项目使用 Firebase 身份验证后,我发现这不是 Firebase 身份验证的问题,而是应用程序的 main 方法的问题。因此,上述各种 Firebase 身份验证实现在部署到 AppEngine 时将按预期工作。
解决方案
我希望应用程序的 main 方法在应用程序部署到 AppEngine 后运行,类似于在 IntelliJ 中运行应用程序的 main 方法时的调用方式。但是我意识到只有在调用应用程序的托管路由后才会调用 main 。
即:https://[yourProjectName].appspot.com
我创建了一个新的 *** 帖子以确定how to run a Ktor app's main method automatically once deployed。
【讨论】:
以上是关于Firebase 身份验证不适用于 AppEngine 上的 Ktor 应用程序的主要内容,如果未能解决你的问题,请参考以下文章