android - 如何从 Android 获取 idtoken 并发布到服务器后端 node.js
问题描述
我一直在尝试将使用 google 登录从 android 应用程序获取的 idToken 发送到服务器。但我没有得到任何结果。我已经按照文档进行操作,但无济于事。
在 logcat 我得到:Unable to POST to http://localhost:5000/auth/google
关于如何解决这个问题的解释或例子会很棒。
我将数据存储在mongodb中。
文档:添加 Google 登录
常数:
- 网址:http://localhost:5000
- client_id : *****gmun****qv2vl55h7k.apps.googleusercontent.com
- client_secret:***MI3k17NCiHBj_elXt
- 重定向网址:http://localhost:5000/auth/google/callback
安卓部分:
activity_auth.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.AuthActivity">
<com.google.android.gms.common.SignInButton
android:id="@+id/sign_in_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="60dp"
android:layout_marginEnd="60dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.84000003" />
</androidx.constraintlayout.widget.ConstraintLayout>
验证活动.kt
class AuthActivity : AppCompatActivity() {
private lateinit var googleSignInClient: GoogleSignInClient
private var signIn = 9001
private val tag = "AuthActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_auth)
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.server_client_id))
.requestEmail()
.build()
googleSignInClient = GoogleSignIn.getClient(this,gso)
sign_in_button.setOnClickListener {
signIn()
}
}
private fun signIn(){
val signInIntent = googleSignInClient.signInIntent
startActivityForResult(signInIntent, signIn)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == signIn){
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
//add silent sign in later on
handleSignInResult(task)
}
}
private fun handleSignInResult(completedTask : Task<GoogleSignInAccount>){
try {
val account = completedTask.getResult(ApiException::class.java)
val idToken = account?.idToken
//send id token to server and validate
ConnectURLTask().execute(idToken)
onLoggedIn(account)
}
catch (e : ApiException){
Log.w(tag, "sign in failed , code : " + e. statusCode)
onLoggedIn(null)
}
}
private fun onLoggedIn(account: GoogleSignInAccount?){
if (account != null){
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
}else{
Toast.makeText(this@AuthActivity, "No Internet Connection", Toast.LENGTH_SHORT).show()
}
}
private class ConnectURLTask : AsyncTask<String, Void, Void>() {
val tag = "Authentication"
override fun doInBackground(vararg strings: String?): Void? {
val httpClient: HttpClient = DefaultHttpClient()
val httpPost = HttpPost("http://localhost:5000/auth/google")
try {
val nameValuePairs: MutableList<NameValuePair> = ArrayList(1)
nameValuePairs.add(BasicNameValuePair("idToken", strings[0]))
httpPost.entity = UrlEncodedFormEntity(nameValuePairs)
val response: HttpResponse = httpClient.execute(httpPost)
val statusCode = response.statusLine.statusCode
val responseBody = EntityUtils.toString(response.entity)
Log.i(tag, "Signed in as: $responseBody")
} catch (e: ClientProtocolException) {
Log.e(tag, "Error sending ID token to backend.", e)
} catch (e: IOException) {
Log.e(tag, "Error sending ID token to backend.", e)
}
return null
}
}
}
节点
用户.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userSchema = new Schema({
googleId : {
type : String,
required : true
},
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true
},
date: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('user', userSchema);
服务器.js
const express = require('express');
const mongoose = require('mongoose');
const path = require('path');
const app = express();
require('dotenv').config();
const { OAuth2Client } = require('google-auth-library');
const User = require('./models/User');
//Connect to DB
mongoose.set('useCreateIndex', true);
mongoose.connect(
process.env.CONNECTION, { useNewUrlParser: true, useUnifiedTopology: true },
() => console.log('Connected!')
);
const client = new OAuth2Client(
process.env.client_id,
process.env.client_secret,
process.env.redirect_url
);
app.post('/auth/google', (req, res) => {
console.log('Evaluating post');
const { idToken } = req.body;
verify(idToken).catch(console.error);
});
//Verify Token method
async function verify(token) {
const ticket = await client.verifyIdToken({
idToken: token,
audience: keystore.client_id
});
const payload = await ticket.getPayload();
const userid = await payload['sub'];
console.log(userid);
User.findOne({ googleId: userid }).then(existingUser => {
if (!existingUser) {
new User({ googleId: userid }).save();
}
});
}
//Port Listener
let PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`server is listening on port ${PORT}`);
});
您的帮助将不胜感激...谢谢
解决方案
推荐阅读
- arrays - 如何在逗号后打印没有空格的数组
- r - 按最近的日期和 ID 合并两个数据框
- c++ - 将值从指针复制到常量对象参数
- java - 将字节传递给采用 UInt8 (Java) 的方法
- php - ASCII 转换器显示空白,输入错误 - PHP
- cvxpy - 使用 CVXPY 和 DCCP 进行斜坡最小二乘估计
- javascript - discord.js 机器人在本地工作,但不在 Heroku 上
- c - 为什么 snprintf 复制不同的值,即使每次都将相同的变量复制到字符串数组
- c - 由于添加了一个小的二维数组而导致的分段错误
- javascript - 更改 .innerHTML 中的链接颜色