简体   繁体   中英

req.session.captcha is not working on different port in Node.js

I am trying to verify captcha by storing into a req.session object.

The express server is running on 8181 and the client on 3000. But in the verify captcha req.session.captcha is undefined. Please help me.

My server code:

var captchapng = require('captchapng');
var express = require('express');
var app = express();
var session = require('express-session');
var cookieParser = require('cookie-parser');

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");
    next();
  });

app.use(cookieParser());
app.use(session({
    secret: 'abcd',
    resave: false,
    saveUninitialized: false,
    cookie: {maxAge: 1000*60*60*24*30}, //30 days
  }));



app.get('/captcha.png', function (request, response) {
    if(request.url == '/captcha.png') {
        var randNumber = Math.random()*9000+1000;
        var p = new captchapng(80,30,parseInt(randNumber)); // width,height,numeric captcha
        p.color(0, 0, 0, 0);  // First color: background (red, green, blue, alpha)
        p.color(80, 80, 80, 255); // Second color: paint (red, green, blue, alpha)
        var no  = parseInt(randNumber);
        request.session.captcha = no.toString();
        console.log(parseInt(randNumber));
        console.log(request.session);
        var img = p.getBase64();
        var imgbase64 = new Buffer(img,'base64');
        response.writeHead(200, {
            'Content-Type': 'image/png'
        });
        response.end(imgbase64);
    } else response.end('');
})

app.get('/verify-captcha', (req, res) => {
    let captcha = req.query.captcha;
    console.log(captcha, req.session);
    if(req.session.captcha === Number(captcha)){
        res.send({message:'verified'})
    }
    else
        res.send({message: "Not Verified!"})
})

app.listen(8181);

My client code:

index.pug

extends layout

block content
  h1= title
  p Welcome to #{title}
  #image
    img(src="http://localhost:8181/captcha.png")
  #verify
    input(type="text" placeholder="Enter captcha to verify" id="captcha")
    button(type="button") Submit

captcha.js

$(document).ready(function(){
    $('button').click(function(e){
        var captcha = $('#captcha').val();
        alert(captcha)
        $.ajax({
            url: 'http://localhost:8181/verify-captcha?captcha='+captcha,
            type:'GET',
            success: function(data){
                alert(data)
            },
            error: function(err) {
                alert(err);
            }
        })
    })
})

Looks like app.use(cookieParser()); is the problem...

From express-session documentation:

Since version 1.5.0, the cookie-parser middleware no longer needs to be used for this module to work. This module now directly reads and writes cookies on req/res. Using cookie-parser may result in issues if the secret is not the same between this module and cookie-parser.

Remove cookieParser or use the same secret app.use(cookieParser('abcd')); .

Also:

Your client code has a typo:

url: 'http://localhost:8181/verify-captch?captcha='+captcha,

should be

url: 'http://localhost:8181/verify-captcha?captcha='+captcha,

In you server code you are comparing String with Number, should be like this:

app.get('/verify-captcha', (req, res) => {
    let captcha = req.query.captcha;
    console.log(captcha, req.session);
    if(req.session.captcha === captcha){ // removed Number() here
        res.send({message:'verified'})
    }
    else
        res.send({message: "Not Verified!"})
})

Edit:

Looks like for $.ajax to send cookies you have to add

xhrFields: {
  withCredentials: true
},

Final client code:

$(document).ready(function(){
    $('button').click(function(e){
        var captcha = $('#captcha').val();
        alert(captcha)
        $.ajax({
            url: 'http://localhost:8181/verify-captcha?captcha='+captcha,
            type:'GET',
            xhrFields: {
              withCredentials: true
            },
            success: function(data){
                console.log(data)
            },
            error: function(err) {
                console.error(err);
            }
        })
    })
})

Working example: https://stackblitz.com/edit/js-y6dzda (note: requires server running on localhost:8181)

Seems you haven't set your session as it should, change lines as follows:

app.get('/captcha.png', function (request, response) {
var session = request.session; // add this 
if(request.url == '/captcha.png') {
    var randNumber = Math.random()*9000+1000;
    var p = new captchapng(80,30,parseInt(randNumber)); // width,height,numeric captcha
    p.color(0, 0, 0, 0);  // First color: background (red, green, blue, alpha)
    p.color(80, 80, 80, 255); // Second color: paint (red, green, blue, alpha)
    var no  = parseInt(randNumber);
    session.captcha = no.toString(); //change this line
    console.log(parseInt(randNumber));
    console.log(session); // and change this
    var img = p.getBase64();
    var imgbase64 = new Buffer(img,'base64');
    response.writeHead(200, {
        'Content-Type': 'image/png'
    });
    response.end(imgbase64);
} else response.end('');
})

this should set the session, because you were assigning no.toString() to request.session.captcha which isn't yet set, what exists instead is request.session.

This is an older issue but I faced the exact same scenario today. Some hours of searching found this workaround.

My environment :

  • Angular CLI: 9.1.6
  • Node: 10.16.2
  • OS: win32 x64
  • Angular: 9.1.7

If there is a better way do let all know. Steps I tried and was not successful:

  • Tried the withCredentials: true - but did nor work for me as I have CORs enabled and it is not allowed as part of the content protection policy.
  • As OP pointed out Some how my session data was sent with each request (each time "undefined")

It all depends on the way you are planning the CAPTCHA (in this particular case) In my case - I'm using a sessionStore (part of request) that contains a list of all sessions from user perspective. Each try is considered as a session. For the login screen I always consider using the last - but each case could be different.

What I ended up doing is to iterate and pick the last item from the list and I did get the captcha data element.

var captchaFromUser = "";
    if(req.sessionStore){
        if(req.sessionStore.sessions){
            var idKeys = Object.keys(req.sessionStore.sessions);
            if(req.sessionStore.sessions[idKeys[idKeys.length-1]]){
                 captchaFromUser =
                 JSON.parse(req.sessionStore.sessions[idKeys[idKeys.length-1]]).captcha;
            }
        }

    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM