我遇到 Node Express 和 CSurf 问题 - 403(禁止)无效的 csrf 令牌。查看其他答案并尝试通过搜索找到的所有内容,我只是无法克服这一点。
我在postman中测试了api,它工作得很好。
当我尝试在登录表单上使用它时,它不起作用。
后端代码:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
// var session = require('client-sessions');
var session = require('express-session');
var flash = require('connect-flash');
var csrf = require('csurf');
var cors = require('cors');
//======== newly added =====
// var csrfProtection = csrf({ cookie: true });
//==== end of all ==========
// var RedisStore = require('connect-redis')(session);
// var fileUpload = require('express-fileupload');
var app = express();
// app.use(fileUpload());
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.json({limit: '100mb'}));
app.use(bodyParser.urlencoded({limit: '100mb', extended: true, parameterLimit:50000}));
app.use(cors());
app.options('*', cors());
app.use(cookieParser());
app.set('trust proxy', 1) // trust first proxy
app.use(session({
secret : 'irutirutiurtuiru',
expires : new Date(Date.now() + 3600000),
resave : false,
saveUninitialized : true,
}));
app.use(flash());
//To disable x-powered-by details in header
app.disable('x-powered-by');
app.use(csrf({ cookie: true }));
var index = require('./routes/index');
var users = require('./routes/users');
var tags = require('./routes/tags');
var access = require('./routes/access');
var brand = require('./routes/brand');
var user = require('./routes/user');
var article = require('./routes/article');
var articlenew = require('./routes/articlenew');
// var imageUpload = require('./routes/imageUpload');
var faq = require('./routes/faq');
var login = require('./routes/login');
var admin = require('./routes/admins');
var editorpick = require('./routes/editorpick');
var log = require('./routes/log');
var articleadminview = require('./routes/articleadminview');
var logout = require('./routes/logout');
var domain = require('./routes/domain');
var banner = require('./routes/banner');
var bannerview = require('./routes/bannerview');
var moderater = require('./routes/moderater');
var poll = require('./routes/poll');
var articleviewcount = require('./routes/articleviewcount');
var report = require('./routes/report');
var whitepaper = require('./routes/whitepaper');
var changepassword = require('./routes/changepassword');
var editprofile = require('./routes/editprofile');
app.use(require('stylus').middleware(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
// app.use('/users', users);
app.use('/tags',tags);
app.use('/access', access);
app.use('/brand', brand);
app.use('/user', user);
app.use('/article', article);
app.use('/articlenew', articlenew);
// app.use('/imageUpload', imageUpload);
app.use('/faq', faq);
app.use('/login', login);
app.use('/admins', admin);
app.use('/editorpick', editorpick);
app.use('/log', log);
app.use('/articleadminview', articleadminview);
app.use('/logout', logout);
app.use('/domain', domain);
app.use('/banner', banner);
app.use('/bannerview', bannerview);
app.use('/moderater', moderater);
app.use('/poll', poll);
app.use('/articleviewcount',articleviewcount);
app.use('/report', report);
app.use('/whitepaper', whitepaper);
app.use('/changepassword', changepassword);
app.use('/editprofile', editprofile);
//client session
// app.use(session({
// cookieName: 'session',
// secret: 'random_string_goes_here',
// duration: 30 * 60 * 1000,
// activeDuration: 5 * 60 * 1000,
// }));
// app.use(session({
// secret: 'fnss0893oin$(@&',
// resave: false,
// saveUninitialized: true
// }));
// catch 404 and forward to error handler
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");
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.locals._csrf = req.csrfToken();
// if(err.code == 'EBADCSRFTOKEN'){
// res.render('csrfError');
// }
// render the error page
res.status(err.status || 500);
// res.render('404');
res.render('error');
});
module.exports = app;
前端代码:
$(function(){
loginPage();
});
function loginPage(){
$('#footer').load('footer', function(){
$('.footer').addClass('posAbs');
});
$('.preloader').fadeOut();
$(document).on('click', '#signin', function() {
//Retrieving the input values
login();
});
$( "#loginpass" ).on( "keydown", function(event) {
if(event.which == 13){
login();
}
});
$('.forgot-btn').on('click', function(){
$(".loginContainer").fadeOut(400, function(){
$(".resetContainer").fadeIn(400);
});
});
$('.resetpass-btn').on('click', function(){
forgotPass();
});
$( ".emailId" ).on( "keydown", function(event) {
if(event.which == 13){
forgotPass();
}
});
$('.notifycontent, .submitted').hide();
$('.notifya').on('click', function(){
$('.notifyMain').hide();
$('.notifycontent').show();
})
$(document).on('click', '.notifysubmit', function(){
var email = $('#notifyEmail').val();
if(email == ""){
var h = $('#notifyEmail').parent().find('.highlighter');
h.show();
h.addClass('shake animated');
$('#notifyEmail').addClass('error');
h.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() {
$(this).removeClass("shake animated");
setTimeout(function() {
h.fadeOut(300);
}, 5000);
});
return false;
}
else if(email != ""){
var expr = /^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/;
if(!expr.test(email)){
var h = $('#notifyEmail').parent().find('.highlighter');
h.show().html('Enter a valid Email');
h.addClass('shake animated');
$('#notifyEmail').addClass('error');
h.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() {
$(this).removeClass("shake animated");
setTimeout(function() {
h.fadeOut(300);
}, 5000);
});
return false;
}
else{
mailAdmin(email);
$('#notifyadmin').modal('hide');
}
}
});
inputValidate();
}
function loginerror() {
var email = $('.email').val();
var password = $('.password').val();
if(email == ''){
var h = $('.email').parent().find('.highlighter');
h.show();
h.addClass('shake animated');
$('.email').addClass('error');
h.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() {
$(this).removeClass("shake animated");
setTimeout(function() {
h.fadeOut(300);
}, 5000);
});
}
else if(password == ''){
var h = $('.password').parent().find('.highlighter');
h.show();
h.addClass('shake animated');
$('.password').addClass('error');
h.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() {
$(this).removeClass("shake animated");
setTimeout(function() {
h.fadeOut(300);
}, 5000);
});
}
}
function forgotPass(){
var emailId = $('.emailId').val();
var emailRegex = new RegExp(/^([\w\.\-]+)@([\w\-]+)((\.(\w){2,3})+)$/i);
var valid = emailRegex.test(emailId);
if (!valid) {
var h = $('.emailId').parent().find('.highlighter');
h.show();
h.addClass('shake animated');
$('.emailId').addClass('error');
h.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() {
$(this).removeClass("shake animated");
setTimeout(function() {
h.fadeOut(300);
}, 5000);
});
return false;
} else{
$('.preloader').fadeIn(300);
forgotPassword(emailId);
}
}
function forgotPassword(email){
var settings = {
"url": base_url+"/forgotpassword/"+email,
"method": "GET",
"async" : true,
};
$.ajax(settings).done(function(data) {
if (data.status === true) {
$('#resetPass h4').html('Your password reset link has been mailed to '+email);
$('.preloader').fadeOut(300);
$('#resetPass').modal('show');
pageCheck = "reset"
}
else {
checkactiveUser(email, pageCheck);
}
}).fail(function(jqXHR, textStatus, errorThrown) {
if (jqXHR.status == 403 || jqXHR.status == 405) {
console.log('Server error. ' + jqXHR.status + '. ' + textStatus + '. ' + errorThrown);
forgotPassword();
}
console.log('Server error. Please try again.');
});
}
function login(){
var email = $('.email').val();
var password = $('.password').val();
var csrfToken = fetchtoken();
pageCheck = "login"
if ((email != '') && (password != '')) {
var settings = {
"url": base_url+"/login",
"method": "POST",
dataType: 'json',
// headers: {
// "x-CSRF-token": csrfToken,
// },
data:{
"email": email,
"password": password,
// "_csrf": csrfToken
},
crossdomain : true
};
$.ajax(settings).done(function(data) {
if (data.status === true) {
alert();
// var data = data.data;
// token = data.accesstoken;
// var userId = data.id;
// localStorage.setItem('userId', userId);
// localStorage.setItem('token', token);
// var userInfo = JSON.stringify(data);
// localStorage.setItem('pollVisited', data.pollVisitedFlag);
// window.open('home', '_self');
}
else {
if(data.msg == "Email id doesnt exist"){
$('#loginError').modal('show');
}
else{
$('.preloader').fadeIn();
checkactiveUser(email, pageCheck);
// var h = $('.password').parent().find('.highlighter');
// h.show().html('Enter a valid password');
// h.addClass('shake animated');
// $('.password').addClass('error');
// h.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() {
// $(this).removeClass("shake animated");
// setTimeout(function() {
// h.fadeOut(300);
// }, 5000);
// });
}
}
}).fail(function(jqXHR, textStatus, errorThrown) {
if (jqXHR.status == 403 || jqXHR.status == 405 || jqXHR.status == 502) {
console.log('Server error. ' + jqXHR.status + '. ' + textStatus + '. ' + errorThrown);
loginPage();
}
console.log(jqXHR.status + textStatus + errorThrown);
});
} else {
loginerror();
}
}
function inputValidate(){
$('input').focus(function(){
$(this).removeClass('error');
$('.highlighter').fadeOut(300);
});
}
function logintimeLog(token){
var settings = {
"url": base_url+"/logintimelog/"+ token,
"method": "GET",
};
$.ajax(settings).done(function(data) {
if (data.status === true) {
console.log('log in');
} else {
console.log('Response status is false');
logintimeLog();
}
}).fail(function(jqXHR, textStatus, errorThrown) {
if (jqXHR.status == 403 || jqXHR.status == 405 || jqXHR.status == 502) {
console.log('Server error. ' + jqXHR.status + '. ' + textStatus + '. ' + errorThrown);
logintimeLog();
}
console.log('Server error. Please try again.');
logintimeLog();
});
}
function checkactiveUser(email, x){
var settings = {
"url": base_url+"/userexist",
"method": "POST",
data:{
"email": email,
}
};
$.ajax(settings).done(function(data) {
if (data.status === true) {
if(data.active === 0){
$('.verify-btn').attr('disabled', true).removeClass('green').addClass('disabled');
$('#onboarding h4').html('Your account is verified.');
$('#onboarding p').html('Complete your sign-up to start using RMA.');
$('#onboarding .sign-here').hide();
$('#onboarding .black-filled').html('Okay');
$('#onboarding').modal('show');
$('.preloader').fadeOut(300);
}
else{
if(x == 'login'){
$('.preloader').fadeOut(300);
var h = $('.password').parent().find('.highlighter');
h.show().html('Enter a valid password');
h.addClass('shake animated');
$('.password').addClass('error');
h.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() {
$(this).removeClass("shake animated");
setTimeout(function() {
h.fadeOut(300);
}, 5000);
});
}
else{
$('.preloader').fadeOut(300);
$('#onboarding').modal('show');
}
}
}
else{
if(x == "reset"){
$('#notifyadmin').modal('show');
}
if(x == 'login'){
var h = $('.password').parent().find('.highlighter');
h.show().html('Enter a valid password');
h.addClass('shake animated');
$('.password').addClass('error');
h.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() {
$(this).removeClass("shake animated");
setTimeout(function() {
h.fadeOut(300);
}, 5000);
});
}
}
}).fail(function(jqXHR, textStatus, errorThrown) {
if (jqXHR.status == 403 || jqXHR.status == 405) {
console.log('Server error. ' + jqXHR.status + '. ' + textStatus + '. ' + errorThrown);
emailVerification();
}
console.log('Server error. Please try again.');
});
}
function mailAdmin(email){
$('.preloader').fadeIn();
var settings = {
"url": base_url+"/mailtoadmin",
"method": "POST",
data:{
"email": email,
}
};
$.ajax(settings).done(function(data) {
if (data.status === true) {
$('.notifycontent').hide();
$('.submitted').show();
$('#notifyadmin').modal('show');
$('.preloader').fadeOut();
}
}).fail(function(jqXHR, textStatus, errorThrown) {
if (jqXHR.status == 403 || jqXHR.status == 405) {
console.log('Server error. ' + jqXHR.status + '. ' + textStatus + '. ' + errorThrown);
emailVerification();
}
console.log('Server error. Please try again.');
});
}
function fetchtoken(){
var settings = {
"url": base_url+"/fetchtoken",
"method": "GET",
};
$.ajax(settings).done(function(data) {
$('input[name="_csrf"]').val(data.token);
return data.token;
}).fail(function(jqXHR, textStatus, errorThrown) {
if (jqXHR.status == 403 || jqXHR.status == 405) {
console.log('Server error. ' + jqXHR.status + '. ' + textStatus + '. ' + errorThrown);
fetchtoken();
}
console.log('Server error. Please try again.');
});
}
更新:响应标头 [/fetchtoken]
HTTP/1.1 200 OK
Server: nginx
Date: Sat, 25 Feb 2017 13:14:44 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 48
Connection: keep-alive
Access-Control-Allow-Origin: *
set-cookie: _csrf=2bd-cKtDQuEeKrACQAJr-Rhu; Path=/
set-cookie: connect.sid=s%3AMIz1TNRpYTI7Pk8uO6MgzOd5M6a31cyW.0RYKkWw9w6om7GGQSawE89hDskJJ5nQ7HZdI24jdmF8; Path=/; HttpOnly
ETag: W/"30-GhAlz0fz9nu44Q5ZUCXJSw"
Cache-Control: max-age=0, no-cache, no-store, must-revalidate
Pragma: no-cache
X-Xss-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
更新:响应标头[登录]
HTTP/1.1 403 Forbidden
Server: nginx
Date: Sat, 25 Feb 2017 13:14:44 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Access-Control-Allow-Origin: *
set-cookie: _csrf=WOF-6ruV7OretakTDESz0gdv; Path=/
set-cookie: connect.sid=s%3A6ft632U8-ykvlzSrUiPcBM4ULBHtIl_A.FuiSoiQ6%2BC22ThR%2Br5PwwHgCLP1nve2mFSLwoluLJTs; Path=/; HttpOnly
ETag: W/"445-JIguc6Asgpp7T6tcOBhH9w"
Content-Encoding: gzip
HTML 元素:
<input id="_csrf" type="hidden" value="1Lf4MPRe-vaeSnvXKNmDIlGIBx4epL6izVFA" name="_csrf">
您使用
fetchtoken
函数就好像它是同步的,但实际上它是异步的。
尝试将
fetchtoken
函数替换为:
function fetchtoken(){
var settings = {
"url": base_url+"/fetchtoken",
"method": "GET",
};
return $.ajax(settings).done(function(data) {
return data.token;
}).fail(function(jqXHR, textStatus, errorThrown) {
if (jqXHR.status == 403 || jqXHR.status == 405) {
console.log('Server error. ' + jqXHR.status + '. ' + textStatus + '. ' + errorThrown);
return fetchtoken();
}
return null;
console.log('Server error. Please try again.');
});
}
并将您的
login
函数替换为:
function login(){
var email = $('.email').val();
var password = $('.password').val();
pageCheck = "login"
fetchtoken().then(function(csrfToken) {
if ((email != '') && (password != '')) {
var settings = {
"url": base_url+"/login",
"method": "POST",
dataType: 'json',
data:{
"email": email,
"password": password,
"_csrf": csrfToken
},
crossdomain : true
};
$.ajax(settings).done(function(data) {
if (data.status === true) {
alert("Logged in!");
// var data = data.data;
// token = data.accesstoken;
// var userId = data.id;
// localStorage.setItem('userId', userId);
// localStorage.setItem('token', token);
// var userInfo = JSON.stringify(data);
// localStorage.setItem('pollVisited', data.pollVisitedFlag);
// window.open('home', '_self');
}
else {
if(data.msg == "Email id doesnt exist"){
$('#loginError').modal('show');
}
else{
$('.preloader').fadeIn();
checkactiveUser(email, pageCheck);
// var h = $('.password').parent().find('.highlighter');
// h.show().html('Enter a valid password');
// h.addClass('shake animated');
// $('.password').addClass('error');
// h.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() {
// $(this).removeClass("shake animated");
// setTimeout(function() {
// h.fadeOut(300);
// }, 5000);
// });
}
}
}).fail(function(jqXHR, textStatus, errorThrown) {
if (jqXHR.status == 403 || jqXHR.status == 405 || jqXHR.status == 502) {
console.log('Server error. ' + jqXHR.status + '. ' + textStatus + '. ' + errorThrown);
loginPage();
}
console.log(jqXHR.status + textStatus + errorThrown);
});
} else {
loginerror();
}
});
}
尽管发送了 CSRF 令牌和其他相关的 CSRF 标头,我还是收到了相同的错误 403。我在代码中发现的问题是,我在同一工作流程中为每个 REST API 调用使用新的 http 客户端实例。当我在整个工作流程中使用相同的实例时,错误得到解决。