获取 ForbiddenError:无效的 csrf 令牌(使用 firebase auth、autodesk forge 和 node.js)
Posted
技术标签:
【中文标题】获取 ForbiddenError:无效的 csrf 令牌(使用 firebase auth、autodesk forge 和 node.js)【英文标题】:Getting ForbiddenError: invalid csrf token (Working with firebase auth, autodesk forge, and node.js) 【发布时间】:2021-04-11 06:39:48 【问题描述】:在使用 firebase auth 和 Autodesk forge 时遇到问题。我使用 csurf 创建用户会话的 cookie,以便使用 firebase 身份验证。实施 csurf 后,我得到错误,为什么我尝试使用 Autodesk forge 功能之一:
responseText: ""message":"invalid csrf token","code":"EBADCSRFTOKEN""
来自我的forgeTree文件,第55行(第55行所在的函数在下面用**突出显示),代码如下:
$(document).ready(function ()
prepareAppBucketTree();
$('#refreshBuckets').click(function ()
$('#appBuckets').jstree(true).refresh();
);
$('#createNewBucket').click(function ()
createNewBucket();
);
$('#createBucketModal').on('shown.bs.modal', function ()
$("#newBucketKey").focus();
);
$('#hiddenUploadField').change(function ()
var node = $('#appBuckets').jstree(true).get_selected(true)[0];
var _this = this;
if (_this.files.length == 0) return;
var file = _this.files[0];
switch (node.type)
case 'bucket':
var formData = new FormData();
formData.append('fileToUpload', file);
formData.append('bucketKey', node.id);
$.ajax(
url: '/api/forge/oss/objects',
data: formData,
processData: false,
contentType: false,
type: 'POST',
success: function (data)
$('#appBuckets').jstree(true).refresh_node(node);
_this.value = '';
);
break;
);
);
**function createNewBucket()
var bucketKey = $('#newBucketKey').val();
jQuery.post(
url: '/api/forge/oss/buckets',
contentType: 'application/json',
data: JSON.stringify( 'bucketKey': bucketKey ),
success: function (res)
$('#appBuckets').jstree(true).refresh();
$('#createBucketModal').modal('toggle');
,
error: function (err)
if (err.status == 409)
alert('Bucket already exists - 409: Duplicated');
console.log(err);
);
**
function prepareAppBucketTree()
$('#appBuckets').jstree(
'core':
'themes': "icons": true ,
'data':
"url": '/api/forge/oss/buckets',
"dataType": "json",
'multiple': false,
"data": function (node)
return "id": node.id ;
,
'types':
'default':
'icon': 'glyphicon glyphicon-question-sign'
,
'#':
'icon': 'glyphicon glyphicon-cloud'
,
'bucket':
'icon': 'glyphicon glyphicon-folder-open'
,
'object':
'icon': 'glyphicon glyphicon-file'
,
"plugins": ["types", "state", "sort", "contextmenu"],
contextmenu: items: autodeskCustomMenu
).on('loaded.jstree', function ()
$('#appBuckets').jstree('open_all');
).bind("activate_node.jstree", function (evt, data)
if (data != null && data.node != null && data.node.type == 'object')
$("#forgeViewer").empty();
var urn = data.node.id;
getForgeToken(function (access_token)
jQuery.ajax(
url: 'https://developer.api.autodesk.com/modelderivative/v2/designdata/' + urn + '/manifest',
headers: 'Authorization': 'Bearer ' + access_token ,
success: function (res)
if (res.status === 'success') launchViewer(urn);
else $("#forgeViewer").html('The translation job still running: ' + res.progress + '. Please try again in a moment.');
,
error: function (err)
var msgButton = 'This file is not translated yet! ' +
'<button class="btn btn-xs btn-info" onclick="translateObject()"><span class="glyphicon glyphicon-eye-open"></span> ' +
'Start translation</button>';
$("#forgeViewer").html(msgButton);
);
);
);
function autodeskCustomMenu(autodeskNode)
var items;
switch (autodeskNode.type)
case "bucket":
items =
uploadFile:
label: "Upload file",
action: function ()
uploadFile();
,
icon: 'glyphicon glyphicon-cloud-upload'
;
break;
case "object":
items =
translateFile:
label: "Translate",
action: function ()
var treeNode = $('#appBuckets').jstree(true).get_selected(true)[0];
translateObject(treeNode);
,
icon: 'glyphicon glyphicon-eye-open'
;
break;
return items;
function uploadFile()
$('#hiddenUploadField').click();
function translateObject(node)
$("#forgeViewer").empty();
if (node == null) node = $('#appBuckets').jstree(true).get_selected(true)[0];
var bucketKey = node.parents[0];
var objectKey = node.id;
jQuery.post(
url: '/api/forge/modelderivative/jobs',
contentType: 'application/json',
data: JSON.stringify( 'bucketKey': bucketKey, 'objectName': objectKey ),
success: function (res)
$("#forgeViewer").html('Translation started! Please try again in a moment.');
,
);
这是我的 start.js 文件,它定义了 csrf 中间件:
const cookieParser = require('cookie-parser');
const csrf = require('csurf');
const path = require('path');
const bodyParser = require("body-parser");
const express = require('express');
const ejs = require("ejs");
const admin = require("firebase-admin");
var serviceAccount = require("./serviceAccountKey.json");
admin.initializeApp(
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://firebasedatabaselink.com"
);
const PORT = process.env.PORT || 3000;
const config = require('./config');
if (config.credentials.client_id == null || config.credentials.client_secret == null)
console.error('Missing FORGE_CLIENT_ID or FORGE_CLIENT_SECRET env. variables.');
return;
const app = express();
app.use('/public', express.static(path.join(__dirname, 'public')));
app.set("view engine", "ejs");
app.use(cookieParser());
app.use(bodyParser.json());
const csrfMiddleware = csrf(
cookie: true
);
app.use(csrfMiddleware);
app.use(express.json(
limit: '50mb'
));
app.use('/api/forge/oauth', require('./routes/oauth'));
app.use('/api/forge/oss', require('./routes/oss'));
app.use('/api/forge/modelderivative', require('./routes/modelderivative'));
app.use((err, req, res, next) =>
console.error(err);
res.status(err.statusCode).json(err);
);
app.all("*", (req, res, next) =>
res.cookie("XSRF-TOKEN", req.csrfToken());
next();
);
app.get("/", function(req, res)
res.render("login");
);
app.get("/register", function(req, res)
res.render("register");
);
app.get("/view", function(req, res)
const sessionCookie = req.cookies.session || "";
admin
.auth()
.verifySessionCookie(sessionCookie, true /** checkRevoked */ )
.then(() =>
res.render("view");
)
.catch((error) =>
res.render("login");
);
);
app.post("/sessionLogin", (req, res) =>
const idToken = req.body.idToken.toString();
const expiresIn = 60 * 60 * 24 * 5 * 1000;
admin
.auth()
.createSessionCookie(idToken,
expiresIn
)
.then(
(sessionCookie) =>
const options =
maxAge: expiresIn,
httpOnly: true
;
res.cookie("session", sessionCookie, options);
res.end(JSON.stringify(
status: "success"
));
,
(error) =>
res.status(401).send("UNAUTHORIZED REQUEST!");
);
);
app.get("/sessionLogout", (req, res) =>
res.clearCookie("session");
res.redirect("/login");
);
app.listen(PORT, () =>
console.log(`Server listening on port $PORT`);
);
这里是 firebaseauthentication.js 文件:
const signupForm = document.querySelector('#signup-form');
const logout = document.querySelector('#logout');
const loginForm = document.querySelector('#login-form');
// listen for auth status changes
auth.onAuthStateChanged(user =>
if (user)
console.log("user logged in:", user);
else
console.log("user logged out");
);
if (document.querySelector('#signup-form') !== null)
// register
signupForm.addEventListener('submit', (e) =>
e.preventDefault();
// get user info
const email = signupForm['signup-email'].value;
const password = signupForm['signup-password'].value;
// register the user
auth.createUserWithEmailAndPassword(email, password).then(cred =>
// console.log(cred.user);
signupForm.reset();
);
);
else if (document.querySelector('#login-form') !== null)
document
.getElementById("login-form")
.addEventListener("submit", (event) =>
event.preventDefault();
const login = loginForm['login-email'].value;
const password = loginForm['login-password'].value;
firebase
.auth()
.signInWithEmailAndPassword(login, password)
.then((
user
) =>
return user.getIdToken().then((idToken) =>
return fetch("/sessionLogin",
method: "POST",
headers:
Accept: "application/json",
"Content-Type": "application/json",
"CSRF-Token": Cookies.get("XSRF-TOKEN"),
,
body: JSON.stringify(
idToken
),
);
);
)
.then(() =>
// loginForm.reset();
return firebase.auth().signOut();
)
.then(() =>
window.location.assign("/view");
);
return false;
);
//logout
logout.addEventListener('click', (e) =>
e.preventDefault();
auth.signOut().then(() =>
window.location.assign("/");
);
);
还有html集成:
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/8.2.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.2.1/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.2.1/firebase-firestore.js"></script>
<script src="https://cdn.jsdelivr.net/npm/js-cookie@rc/dist/js.cookie.min.js"></script>
<!-- TODO: Add SDKs for Firebase products that you want to use
https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/8.2.1/firebase-analytics.js"></script>
<script> id="fbauth"
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
var firebaseConfig =
apiKey: "apinumbersgohere",
authDomain: "firebaseapp.com",
databaseURL: "https:firebasedatabase.com",
projectId: "id",
appId: "id",
measurementId: "id"
;
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();
// make auth and firestore references
const auth = firebase.auth();
const db = firebase.firestore();
auth.setPersistence(firebase.auth.Auth.Persistence.NONE);
// update firestore settings
db.settings(
timestampsInSnapshots: true
);
</script>
<p class="text-center text-muted">© Copyright 2020 Obi Vision</p>
<script src="/public/js/fbauth.js"></script>
</body>
</html>
我怀疑 fortree api 以某种方式抓取了我正在生成的 csurf cookie,而不是它自己的实例化 cookie,但我太菜鸟了,无法发现问题出在哪里。任何愿意帮助我的人都会很有帮助,你不知道
【问题讨论】:
【参考方案1】:Firebase 托管会删除除 __session 之外的所有 cookie,因此您需要在使用会话 cookie 的任何地方进行更改,如下所示,
,,
const sessionCookie = req.cookies.__session || "";
...
res.clearCookie("__session");
下面可能还想更新添加,
app.get("/", function(req, res)
res.clearCookie("__session");
res.render("login");
);
Yesterday i had posted similar didnt get any response yet
今天我在不同的页面上遇到了和你一样的错误。
【讨论】:
谢谢你! "res.clearCookie("__session");"成功了! 我试过了,但我还没有足够的积分。你必须让我有幸投票支持我的第一个问题才能给我这个特权以上是关于获取 ForbiddenError:无效的 csrf 令牌(使用 firebase auth、autodesk forge 和 node.js)的主要内容,如果未能解决你的问题,请参考以下文章
nodejs.ForbiddenError: invalid csrf token解决方案