我正在尝试分配一个生成会话cookie,以换取所提供的ID令牌。 Here是我关注的文档。
这是我的客户端登录代码:
firebase.auth().signInWithEmailAndPassword(email, password)
.then(function(user) {
firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
return sendToken(idToken);
});
})
// .then(() => {
// return firebase.auth().signOut();
// })
.then(() => {
window.location.assign('/member');
})
.catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
alert(errorMessage);
});
我的send sendToken()将idToken发布到服务器:
function sendToken(idToken) {
console.log("Posting " + idToken);
var xhr = new XMLHttpRequest();
var params = `token=${idToken}`;
xhr.open('POST', "/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);
});
}
然后在服务器上,我返回一个会话cookie:
app.post('/login', (req, res) => {
if (req.body.token) {
const idToken = req.body.token.toString();
// Set session expiration to 1 day.
const expiresIn = 60 * 60 * 24 * 1 * 1000;
return firebase.auth().createSessionCookie(idToken, {expiresIn}).then((sessionCookie) => {
const options = {maxAge: expiresIn, httpOnly: true, secure: true};
res.cookie('session', sessionCookie, options);
res.end(JSON.stringify({status: 'success'}));
})
.catch((error) => {
res.status(401).send('UNAUTHORIZED REQUEST!');
});
}
return res.status(400).send("MISSING TOKEN");
});
我还设置了一个中间件,以在服务器提供成员信息之前验证会话cookie:
function authVerification(req, res, next){
const sessionCookie = req.cookies.session || '';
// Verify the session cookie. In this case an additional check is added to
detect
// if the user's Firebase session was revoked, user deleted/disabled, etc.
return firebase.auth().verifySessionCookie(
sessionCookie, true /** checkRevoked */).then((decodedClaims) => {
console.log("decoded claims: " + decodedClaims);
next();
// serveContentForUser('/profile', req, res, decodedClaims);
}).catch(error => {
// Session cookie is unavailable or invalid. Force user to login.
res.send(error);
});
}
但是,当我登录后尝试获取会员页面时:
app.get("/member", authVerification, (req, res) => {
res.send("member page");
});
我不断从authVerification中获取错误:
代码:“ auth / argument-error”, 消息:“解码Firebase会话cookie失败。请确保您传递了代表会话cookie的整个字符串JWT。有关如何检索会话cookie的详细信息,请参见https://firebase.google.com/docs/auth/admin/manage-cookies。”
谁能给我指出正确的方向。预先谢谢你!
答案 0 :(得分:2)
quickstart-nodejs存储库中的解决方案。
您必须添加 cookie-parser 和 body-parser 。这是我使用Firebase Cloud Functions解决的方法:
const admin = require("firebase-admin");
const functions = require("firebase-functions");
const next = require("next");
const cors = require("cors");
const express = require("express");
const cookieParser = require("cookie-parser");
const bodyParser = require("body-parser");
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev, conf: { distDir: "next" } });
const handle = app.getRequestHandler();
admin.initializeApp({
credential: admin.credential.cert("Service account key"),
databaseURL: "Path to database"
});
const server = express();
server.use(cors({ origin: true }));
server.use(bodyParser.json());
// Support URL-encoded bodies.
server.use(bodyParser.urlencoded({
extended: true
}));
// Support cookie manipulation.
server.use(cookieParser());
// Attach CSRF token on each request.
server.use(attachCsrfToken('/', 'csrfToken', (Math.random()* 100000000000000000).toString()));
function attachCsrfToken(url, cookie, value) {
return function(req, res, next) {
if (req.url === url) {
res.cookie(cookie, value);
}
next();
}
}
server.post("/login", (req, res) => {
if (req.body && req.body.idToken) {
const idToken = `${req.body.idToken}`;
const expiresIn = 60 * 60 * 24 * 5 * 1000;
admin.auth().createSessionCookie(idToken, { expiresIn }).then((sessionCookie) => {
const options = { maxAge: expiresIn, httpOnly: true, secure: true };
res.cookie("session", sessionCookie, options);
res.end(JSON.stringify({ sessionCookie }));
}, error => {
res.status(401).send(error);
});
} else {
res.status(401).send("Token empty");
}
});
server.post("/profile", (req, res) => {
if (req.cookies && req.cookies.session) {
const sessionCookie = `${req.cookies.session}`;
admin.auth().verifySessionCookie(
sessionCookie, true /** checkRevoked */).then((decodedClaims) => {
res.end(JSON.stringify({ decodedClaims }));
}).catch(error => {
res.status(401).send(error);
});
} else {
res.status(401).send("Session empty");
}
});
exports.next = functions.https.onRequest((req, res) => {
if (req.method === "POST") {
if (!req.path) req.url = `/${request.url}`;
return server(req, res);
}
return app.prepare().then(() => handle(req, res));
});
客户端没有什么特别的。您可以使用isomorphic-unfetch,axios或jQuery。