【发布时间】:2019-01-19 07:07:18
【问题描述】:
我正在关注此文档:Manage Session Cookies
我的 app.js 看起来像这样,基本上通过单击按钮在客户端登录用户。
(function() {
// Initialize Firebase
var config = {
//...
};
firebase.initializeApp(config);
// no local persistence because of the httpOnly flag
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.NONE);
const emailField = document.getElementById("email");
const passwordField = document.getElementById("password");
const loginButton = document.getElementById("loginButton");
loginButton.addEventListener("click", e => {
const email = emailField.value;
const password = passwordField.value;
const signInPromise = firebase.auth().signInWithEmailAndPassword(email, password);
signInPromise.catch(e => {
console.log("Login Error: " + e.message);
})
return signInPromise.then(() => {
console.log("Signed in + " + firebase.auth().currentUser.uid);
return firebase.auth().currentUser.getIdToken().then(idToken => {
// Session login endpoint is queried and the session cookie is set.
// CSRF protection should be taken into account.
// ...
// const csrfToken = getCookie('csrfToken')
console.log("User ID Token: " + idToken);
return sendToken(idToken);
//return postIdTokenToSessionLogin('/sessionLogin', idToken, csrfToken);
});
})
});
firebase.auth().onAuthStateChanged(user => {
if (user) {
document.getElementById('loginSuccess').innerHTML = `Signed in as ${user.uid}`;
document.getElementById('loginError').innerHTML = "";
} else {
document.getElementById('loginSuccess').innerHTML = "";
document.getElementById('loginError').innerHTML = `Not signed in`;
}
});
})();
sendToken 函数如下所示:
function sendToken(idToken) {
console.log("Posting " + idToken);
var xhr = new XMLHttpRequest();
var params = `token=${idToken}`;
xhr.open('POST', "/admin/login", true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
return new Promise(function(resolve, reject) {
xhr.onreadystatechange = function() {//Call a function when the state changes.
if (xhr.readyState == 4 && xhr.status == 200) {
resolve();
} else if (xhr.readyState == 4 && xhr.status != 200) {
reject("Invalid http return status");
}
}
return xhr.send(params);
});
}
在服务器端,我使用具有托管和 firebase 功能的快速应用程序
/admin/login 的帖子如下所示:
adminApp.post("/login", (request, response) => {
console.log("Got login post request");
if (request.body.token) {
const idToken = request.body.token.toString();
console.log("idToken = " + idToken);
// Set session expiration to 5 days.
const expiresIn = 60 * 60 * 24 * 5 * 1000;
return adminFirebase.auth().createSessionCookie(idToken, {expiresIn}).then((sessionCookie) => {
const options = {maxAge: expiresIn, httpOnly: true, secure: true};
response.cookie('session', sessionCookie, options);
response.end(JSON.stringify({status: 'success'}));
}, error => {
response.status(401).send('UNAUTHORIZED REQUEST!');
});
}
return response.status(400).send("MISSING TOKEN");
});
所以在发布sendToken 之后,我应该有一个名为“会话”的 cookie,其中包含信息。所以现在我写了一个小中间件来检查那个令牌:
const validateLogin = function (req, res, next) {
const sessionCookie = req.cookies.session || '';
console.log(JSON.stringify(req.headers));
console.log("Verifying " + sessionCookie);
return adminFirebase.auth().verifySessionCookie(sessionCookie, true).then((decodedClaims) => {
console.log("decoded claims: " + decodedClaims);
next();
}).catch(error => {
res.redirect('/admin/login');
});
};
最后但同样重要的是,我有一个 admin/secret 正在使用这个中间件:
adminApp.get("/secret/", validateLogin, (request, response) => {
return response.send("This is secret!");
});
然而,我经常被送回登录页面。我缺少什么让 cookie 起作用?
我发现根据this 的 Firebase 托管只允许一个 cookie(否则它们会被剥离)。此 cookie 是 __session,但设置此 cookie 似乎对我也不起作用...
我能够在客户端设置 __session cookie:
document.cookie = "__session=TOKEN"
然后在服务器端验证令牌,但是 cookie 仅适用于本地 / 路径而不适用于 /a/b
【问题讨论】:
标签: firebase cookies firebase-authentication google-cloud-functions firebase-admin