[英]Getting ForbiddenError: invalid csrf token (Working with firebase auth, autodesk forge, and node.js)
使用 firebase auth 和 Autodesk forge 时遇到问题。 我使用 csurf 创建了用户会话的 cookies 以使用 firebase 身份验证。 实施 csurf 后,我得到错误,为什么我尝试使用 Autodesk forge 功能之一:
responseText: "{"message":"invalid csrf token","code":"EBADCSRFTOKEN"}"
从第 55 行指示的我的 forgeTree 文件中(第 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>
我怀疑遗忘者 api 以某种方式抓取了我正在生成的 csurf cookie,而不是它自己的实例化 cookie,但我太菜鸟了,无法发现问题出在哪里。 任何愿意帮助我的人都会很有帮助,你不知道
Firebase 托管剥离除 __session 之外的所有 cookies,因此您需要在使用 session cookie 的任何地方进行更改,如下所示,
,,
const sessionCookie = req.cookies.__session || "";
...
res.clearCookie("__session");
也可能想在下面更新以添加,
app.get("/", function(req, res)
{
res.clearCookie("__session");
res.render("login");
});
今天我在不同的页面上遇到了和你一样的错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.