问题描述
我正在尝试设置CSRF令牌,以便在向客户端颁发令牌以用于将来的请求之前可以进行多次检查.
按照csurf的指导
有什么我做不正确的事情吗?我认为这可能与Node.js的cookie系统有关.
我认为您的问题很可能与CORS有关(您的开发工具可能已发出警告?).
根据文档,这是我能制作的最简单的后端和前端:
在后端(带有Express的NodeJS)服务器中:
在app.js中:
var cookieParser = require('cookie-parser')var csrf = require('csurf')var bodyParser = require('body-parser')var express = require('express')const cors = require('cors');var csrfProtection = csrf({cookie:true})var parseForm = bodyParser.urlencoded({扩展:false})var app = express()const corsOptions = {来源:"http://localhost:3000",凭据:是的,}app.use(cors(corsOptions));app.use(cookieParser())app.get('/form',csrfProtection,function(req,res){res.json({csrfToken:req.csrfToken()})})app.post('/process',parseForm,csrfProtection,function(req,res){res.send('数据正在处理')})module.exports =应用程序;
(确保将 corsOptions
origin
属性更新为React中的本地主机.
在Index.js中:
const app = require('./app')app.set('port',5000);app.listen(app.get('port'),()=> {console.log('App在端口上运行',app.get('port'));});
在React中:
创建文件"TestCsurf.js";并填充以下代码:
从'react'导入React导出默认函数TestCsurf(){让domainUrl =`http://localhost:5000`const [csrfTokenState,setCsrfTokenState] = React.useState('')const [haveWeReceivedPostResponseState,setHaveWeReceivedPostResponseState] = React.useState(尚未.尚未处理任何数据.")异步函数getCallToForm(){const url =`/form`;让fetchGetResponse =等待fetch(`$ {domainUrl} $ {url}`,{方法:"GET",标头:{接受:"application/json","Content-Type":"application/json","xsrf-token":localStorage.getItem('xsrf-token'),},凭据:包括",模式:"cors"})让parsedResponse =等待fetchGetResponse.json();setCsrfTokenState(parsedResponse.csrfToken)}React.useEffect(()=> {getCallToForm()},[])异步功能testCsurfClicked(){const url =`/process`let fetchPostResponse =等待fetch(`$ {domainUrl} $ {url}`,{方法:"POST",标头:{接受:"application/json","Content-Type":"application/json","xsrf-token":csrfTokenState,},凭据:包括",模式:"cors",})让parsedResponse =等待fetchPostResponse.text()setHaveWeReceivedPostResponseState(parsedResponse)}返回 (< div>< button onClick = {testCsurfClicked}>测试Csurf发布呼叫</button>< p> csrfTokenState是:{csrfTokenState}</p>< p>我们是否已成功使用令牌导航csurf ?: {JSON.stringify(haveWeReceivedPostResponseState)}</p></div>)}
将其导入到您的app.js
从'./CsurfTutorial'导入CsurfTutorial;函数App(){返回 (< CsurfTutorial></CsurfTutorial>);}导出默认应用程序;
根据CSURF文档示例,这是我可以做的最简单的解决方案.我花了几天的时间才弄清楚.希望他们能给我们更多的指导!
我制作了一个教程视频,以防对任何人有帮助: https://youtu.be/N5U7KtxvVto
I'm trying to setup CSRF tokens so that I can do a number of checks before issueing a token to the client to use in future requests.
Taking the guidance from the csurf documentation, I've setup my express route with the following:
const express = require('express');
const router = express.Router({mergeParams: true});
const csurf = require('csurf');
const bodyParser = require('body-parser');
const parseForm = bodyParser.urlencoded({ extended: false });
const ErrorClass = require('../classes/ErrorClass');
const csrfMiddleware = csurf({
cookie: true
});
router.get('/getCsrfToken', csrfMiddleware, async (req, res) => {
try {
// code for origin checks removed for example
return res.json({'csrfToken': req.csrfToken()});
} catch (error) {
console.log(error);
return await ErrorClass.handleAsyncError(req, res, error);
}
});
router.post('/', [csrfMiddleware, parseForm], async (req, res) => {
try {
// this returns err.code === 'EBADCSRFTOKEN' when sending in React.js but not Postman
} catch (error) {
console.log(error);
return await ErrorClass.handleAsyncError(req, res, error);
}
});
For context, the React.js code is as follows, makePostRequest
100% sends the _csrf
token back to express in req.body._csrf
try {
const { data } = await makePostRequest(
CONTACT,
{
email: values.email_address,
name: values.full_name,
message: values.message,
_csrf: csrfToken,
},
{ websiteId }
);
} catch (error) {
handleError(error);
actions.setSubmitting(false);
}
Postman endpoint seems to be sending the same data, after loading the /getCsrfToken
endpoint and I manually update the _csrf
token.
Is there something I'm not doing correctly? I think it may be to do with Node.js's cookie system.
I think your problem is likely to be related to CORS (your dev tools will probably have sent a warning?).
Here's the simplest working back-end and front-end I could make, based on the documentation:
In Back-End (NodeJS with Express) Server:
In app.js:
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var bodyParser = require('body-parser')
var express = require('express')
const cors = require('cors');
var csrfProtection = csrf({ cookie: true })
var parseForm = bodyParser.urlencoded({ extended: false })
var app = express()
const corsOptions = {
origin: "http://localhost:3000",
credentials: true,
}
app.use(cors(corsOptions));
app.use(cookieParser())
app.get('/form', csrfProtection, function (req, res) {
res.json({ csrfToken: req.csrfToken() })
})
app.post('/process', parseForm, csrfProtection, function (req, res) {
res.send('data is being processed')
})
module.exports = app;
(make sure you update the corsOptions
origin
property to whatever your localhost is in React.
In Index.js:
const app = require('./app')
app.set('port', 5000);
app.listen(app.get('port'), () => {
console.log('App running on port', app.get('port'));
});
In React:
Create file "TestCsurf.js" and populate with this code:
import React from 'react'
export default function TestCsurf() {
let domainUrl = `http://localhost:5000`
const [csrfTokenState, setCsrfTokenState] = React.useState('')
const [haveWeReceivedPostResponseState, setHaveWeReceivedPostResponseState] = React.useState("Not yet. No data has been processed.")
async function getCallToForm() {
const url = `/form`;
let fetchGetResponse = await fetch(`${domainUrl}${url}`, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"xsrf-token": localStorage.getItem('xsrf-token'),
},
credentials: "include",
mode: 'cors'
})
let parsedResponse = await fetchGetResponse.json();
setCsrfTokenState(parsedResponse.csrfToken)
}
React.useEffect(() => {
getCallToForm()
}, [])
async function testCsurfClicked() {
const url = `/process`
let fetchPostResponse = await fetch(`${domainUrl}${url}`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"xsrf-token": csrfTokenState,
},
credentials: "include",
mode: 'cors',
})
let parsedResponse = await fetchPostResponse.text()
setHaveWeReceivedPostResponseState(parsedResponse)
}
return (
<div>
<button onClick={testCsurfClicked}>Test Csurf Post Call</button>
<p>csrfTokenState is: {csrfTokenState}</p>
<p>Have we succesfully navigates csurf with token?: {JSON.stringify(haveWeReceivedPostResponseState)}</p>
</div>
)
}
Import this into your app.js
import CsurfTutorial from './CsurfTutorial';
function App() {
return (
<CsurfTutorial></CsurfTutorial>
);
}
export default App;
That's the simplest solution I can make based on the CSURF documentations example. It's taken me several days to figure this out. I wish they'd give us a bit more direction!
I made a tutorial video in case it's of any help to anyone: https://youtu.be/N5U7KtxvVto
这篇关于Express.js Csurf在邮递员中工作,但不在React.js中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!