我正在使用带有react前端的nodejs express API。我正在尝试设置csurf xsrf,但是它会继续返回invalid csrf token
。我已经读过有关csrf的文章,并了解它正在解决的问题。
因此,基本上,每次我的react应用程序每次从服务器发出请求时,都会请求一个新令牌。 (我不是很肯定这是正确的。是否只需要在准备发出请求时才请求令牌?)
前端:localhost:3016
后端:localhost:3050
有人知道我在做什么错吗?
这是nodejs app.js文件
// Handler
const Entry = require("./handlers/entry");
const Test = require("./handlers/test");
const {Config,Environments} = require("./common/config");
const Auth = require("./funcs/user/auth");
const ObjectUtil = require("./utils/object");
const AccountStatusEnum = require("./enums/account-status").accountStatusEnum;
// Simulate real API calls
const delayResponse = 250;// milliseconds
// ==============================================
// Base setup
// ==============================================
process.env.TZ = "Etc/GMT"
const express = require('express');
const app = express();
const port = 3050;
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const csrf = require('csurf');
const csrfProtection = csrf({
cookie: true,
path: "/login",
key: "x-csrf-token",
domain: Config.FrontEnd.Url,
});
app.use(bodyParser.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(csrfProtection)
app.use(require('express-useragent').express());
// Cors
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, auth-id, auth-token, x-csrf-token, _csrf");
res.header('Access-Control-Allow-Methods', 'PATCH, POST, GET, DELETE, OPTIONS');
next();
});
// csrf
app.use(function (err, req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, auth-id, auth-token, x-csrf-token, _csrf");
res.header('Access-Control-Allow-Methods', 'PATCH, POST, GET, DELETE, OPTIONS');
// handle CSRF token errors here
if(err.code === 'EBADCSRFTOKEN'){
let foo = req.headers['x-csrf-token'];
res.status(403)
let obj = {
err: {
code:1,
message:err.message,
headerCSRF: foo,
},
res: {},
};
response(req,res,obj);
return;
}
next();
})
// ==============================================
// Auth
// ==============================================
const normRoute = (req, res, next) => {
req.body = (req.body != undefined && req.body != null) ? ObjectUtil.toCamelCaseKeys(req.body) : req.body;
response(req,res,next(req));
}
const authRoute = async (req, res, next, minimumStatus) => {
req.body = (req.body != undefined && req.body != null) ? ObjectUtil.toCamelCaseKeys(req.body) : req.body;
let authId = (req.headers['auth-id'] !== undefined) ? req.headers['auth-id'] :"";
let authToken = (req.headers['auth-token'] !== undefined) ? req.headers['auth-token'] : "";
const r = await Auth.authUser(
req.ip,
req.useragent,
authId,
authToken,
minimumStatus,
);
if(r.err.code){
response(req,res,r);
return false;
}
response(req,res,next(req,r.res.user));
}
// ==============================================
// Routes
// ==============================================
app.get('/', function(req, res) {
res.send('<html><head></head><body>API is running<br> Check the docs for the details</body></html>');
});
app.post('/login', function(req,res) { normRoute(req,res,Entry.postLogin) });
app.post('/logout', function(req,res) { authRoute(req,res,Entry.postLogout,AccountStatusEnum.banned) });
app.get('/test', function(req,res) { normRoute(req,res,Test.get) });
app.post('/test', function(req,res) { authRoute(req,res,Test.post,AccountStatusEnum.basic) });
// ==============================================
// Response type
// ==============================================
const response = async (req,res,obj) => {
await obj;
Promise.resolve(obj).then(function(val) {
if(delayResponse >= 1 && (Config.Env === Environments.Local)){
setTimeout(function(){
resume(req,res,val);
}, delayResponse);
return true;
}
resume(req,res,val);
});
}
const resume = (req,res,obj) => {
obj = (obj === undefined) ? {} : obj;
var status = (obj.status !== undefined) ? obj.status : 200;
// Let status override settings
if(obj.status === undefined){
if((obj.err.code)){
status = 400;
}else if(obj.res === undefined || ObjectUtil.isEmpty(obj.res)){
// status = 204;
}
}
let json = {};
json.err = obj.err;
json.res = obj.res;
let csrfToken = req.csrfToken();
json.csrf = csrfToken;
console.log("json.csrf",json.csrf);
res.cookie('x-csrf-token', csrfToken);
json = ObjectUtil.toCamelCaseKeys(json);
res.status(status).json(json);
}
// ==============================================
// Start the server
// ==============================================
app.listen(process.env.PORT || port);
console.log('Magic happens on port ' + port);
前端将其作为标头发送
// has both in here for testing atm
headers['_csrf'] = (localStorage.getItem("csrf") !== null) ? localStorage.getItem("csrf"): "";
headers['x-csrf-token'] = (localStorage.getItem("csrf") !== null) ? localStorage.getItem("csrf"): "";
这是网络信息
General
Request URL: http://localhost:3050/login
Request Method: POST
Status Code: 400 Bad Request
Remote Address: [::1]:3050
Referrer Policy: no-referrer-when-downgrade
Response
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, auth-id, auth-token, x-csrf-token, _csrf
Access-Control-Allow-Methods: PATCH, POST, GET, DELETE, OPTIONS
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 156
Content-Type: application/json; charset=utf-8
Date: Wed, 13 May 2020 07:17:21 GMT
ETag: W/"9c-PlmNfMbUDSIMeWXLZoHk3lyBG/4"
Set-Cookie: _csrf=ZrkXaXMiYQfyIVaALbG9lJaX; Path=/
Set-Cookie: x-csrf-token=Y603zmAK-wBbU8LMDILCMz4VaodZBdAYfOS4; Path=/
X-Powered-By: Express
Request Headers
_csrf: wPQqioyo-D47QGH0F1fytuUG2JXP2F7uDmFM
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,ja;q=0.8
Connection: keep-alive
Content-Length: 39
Content-Type: application/json
Host: localhost:3050
Origin: http://localhost:3016
Referer: http://localhost:3016/login
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36
x-csrf-token: wPQqioyo-D47QGH0F1fytuUG2JXP2F7uDmFM