javascript - 在 Firebase 中实现会话 cookie 后无法读取 null 的属性“getIdToken”
问题描述
我使用此链接在我的 firebase 项目上实现了 cookie 会话。
我正在尝试让idToken
客户端将其发送到服务器端。
这是我在客户端使用的代码:
$(function(){
$.ajax({
url: "/checkSession",
type: 'post',
success: function(data) {
if(data.status === "ok" && data.user){
const user = data.user;
const emailVerified = user.email_verified;
const uid = user.uid;
if (emailVerified){
firebase.database().ref().child("users").child(uid).child("username").once("value", snapshot => {
const username = snapshot.val();
firebase.auth().currentUser.getIdToken(true).then(idToken => {
// Doesn't work...
})
}).catch(err => {
console.log(err)
});
}
}
}
});
});
这是检查会话的服务器:
app.post("/checkSession", (req, res, next) => {
const sessionCookie = req.cookies.session || '';
admin
.auth()
.verifySessionCookie(sessionCookie, true)
.then(user => {
res.json({
status: "ok",
user
})
})
.catch((error) => {
res.json({
status: "error",
})
});
})
除此功能外,一切正常:firebase.auth().currentUser.getIdToken(true).then(idToken => {...})
并且它正在抛出Cannot read property 'getIdToken' of null
错误。
更新:这是我正在使用的登录方法。我将错误传递给httpOnly
并且secure
因为我在本地对其进行测试。
app.post("/SignInUser", (req, res, next) => {
const idToken = req.body.idToken.toString();
const expiresIn = 60 * 60 * 24 * 10 * 1000; // 10 days
admin
.auth()
.verifyIdToken(idToken)
.then(function (decodedClaims) {
if (new Date().getTime() / 1000 - decodedClaims.auth_time < 5 * 60) {
return admin.auth().createSessionCookie(idToken, { expiresIn });
}
})
.then(function (sessionCookie) {
const options = { maxAge: expiresIn, httpOnly: false, secure: false};
res.cookie("session", sessionCookie, options);
return res.json({
status: "ok"
})
})
.catch(function (error) {
return res.json({
status: "error",
message: "Unauthorized request!"
})
});
})
更新 2:我使用 idToken 来验证来自用户的请求实际上是来自用户而不是来自外部源,这是一个示例代码:
function getUserSnapshotOrVerifyUserId(username, idToken, cb) {
if (username == null || username.length == 0 || idToken == null || idToken.length == 0)
return cb({
status: "error",
errorMessage: "Missing params."
}, null);
admin.auth().verifyIdToken(idToken).then(decodedToken => {
let uid = decodedToken.uid;
admin.database().ref().child("users").orderByChild("username").equalTo(username).once('value', snapshot => {
if (!snapshot.exists())
return cb({
status: "error",
message: "invalid-profile"
});
snapshot.forEach(child => {
const id = child.val().id;
if (id !== uid)
return cb({
status: "error",
message: "Invalid ID"
});
admin.database().ref("users/" + id).once("value", snapshot => {
if (!snapshot.exists())
return cb({
status: "error",
errorMessage: "user not found."
});
return cb(null, id, snapshot);
});
});
});
}).catch(err => cb({
status: "error",
message: err
}));
}
app.post("/getUserProfile", (req, res, next) => {
const username = req.body.username || req.query.username;
const idToken = req.body.idToken;
getUserSnapshotOrVerifyUserId(username, idToken, (err, id, snapshot) => {
if (err) return res.json(err);
let userdata = {
username: snapshot.val().username,
name: snapshot.val().name,
}
res.json({
status: "ok",
userdata
})
})
})
解决方案
Firebase 身份验证是异步的,您需要等待它完全初始化,然后再尝试引用currentUser
. 有关如何执行此操作的更多信息,请参阅此答案。
用更简单的术语来说,您需要在调用任何引用的函数之前监听onAuthStatusChanged()
并等待它返回null
或对象。我会给你具体的代码更改,但相关部分不在问题中。User
currentUser
推荐阅读
- c++ - 检查 std::filesystem::path 是否在目录中
- python-3.x - 它在 DF1 中而不在 DF 中,但仅匹配特定列
- python - 如何在python中全局定义一个列表
- python - 使用 Python ibm_db 包将时间戳更新为 DB2 中的当前时间戳
- python - 如何获取 Pandas Dataframe 的最后一行?
- algorithm - 如果我们在创建 Huffman Tree 时不一致会发生什么?
- android - 为什么 androidx.lifecycle.ViewModelProviders 在“android.arch.lifecycle:extensions”而不是“android.arch.lifecycle:viewmodel”?
- python - pyspark - 如何在分层随机抽样中使用(df.sampleByKey())选择每层的确切记录数
- python - 通过最外面的大括号将字符串拆分为列表
- c++ - 如何使用给定的长度作为对象参数初始化成员数组