Javascript 关于快速会话和cookies,我遗漏了什么?

Javascript 关于快速会话和cookies,我遗漏了什么?,javascript,node.js,session,cookies,express,Javascript,Node.js,Session,Cookies,Express,我已经在express和express会话以及express sql会话方面取得了很大进展。当用户登录时,我在数据库中为会话创建了一行。我是这样设置的: //login route handler this.bcrypt.compare(password, row.hashed, function(err, passwordsMatch) { if (passwordsMatch === true) { console.log("user now logged in");

我已经在express和express会话以及express sql会话方面取得了很大进展。当用户登录时,我在数据库中为会话创建了一行。我是这样设置的:

//login route handler
this.bcrypt.compare(password, row.hashed, function(err, passwordsMatch) {
    if (passwordsMatch === true) {
        console.log("user now logged in");
        req.session.user = row;
        req.session.success = 'User successfully logged in';
        res.send(row);
        res.end();
    }
});
<pre><code>
      fetch(
        "http://localhost:3001/accounts",
        {
            method: "GET",
            headers: {"Content-Type": "application/json"},
            credentials: "include"
        }
    )
</pre></code>
帅哥多莉!我可以跳入会话表并从数据库中获取行。这是:

{"cookie":{"originalMaxAge":600000,"expires":"2015-08-24T23:16:20.079Z","httpOnly":false,"path":"/"},

"user":{"userID":24,"userName":"g","email":"g","joinDate":"2015-08-24T07:15:33.000Z"},"success":"User successfully logged in"}
请注意,您可以看到自定义使用对象已设置。但是,在下一个获取数据的请求中,我检查会话上的
user
对象:

// some other route called after login. 
if (!req.session.user) {
    console.log('user not authorized' + JSON.stringify(req.session));
    res.send('not authorized');
    return;
}
但这记录了一个(显然)空会话

user not authorized{"cookie":{"originalMaxAge":600000,"expires":"2015-08-24T23:27:13.455Z","httpOnly":false,"path":"/"}}
进入浏览器,我还看到资源面板中没有设置cookie。这不应该由express 4和session自动生成吗?文档说您不再需要expressCookie()和Express4。如何在后续请求中获得正确的会话

另外,如果我再次登录,它只会在sessions表中创建一个重复的行如何在响应中正确设置cookie,以便在下一个请求中使用它?

以下是我的会话配置(如果有帮助):

// at the beginning of my node server 

import express = require('express');
import bodyParser = require('body-parser');
import Q = require('q');
import mysql = require('mysql');
var app = express();

import bcrypt = require('bcrypt');

import userModule = require('./userModule')
var UserRepository = new userModule.UserNamespace.UserRepository(connectToMySQL, bcrypt, Q );

import session = require('express-session');
var SessionStore = require('express-sql-session')(session);

app.use(function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header('Access-Control-Allow-Credentials', 'true');
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});

app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())


var storeOptions = {
    client: 'mysql',
    connection: {
        host:SQLHOST,
        port:SQLPORT,
        user:SQLUSER,
        password: SQLPASS,
        database: SQLDB
    },
    table: SESSION_TABLE,
    expires: 365 * 24 * 60 * 60 * 1000
};

var sessionStore = new SessionStore( storeOptions );

app.use(session({
    secret: 'meeogog',
    resave: false,
    saveUninitialized: false,
    cookie: { maxAge: 600000,httpOnly: false },
    store: sessionStore
}));

... 

app.post('/users/login/', function (req, res) {
    UserRepository.loginHashed(req, res);
});

..and then more routes, and so forth

就在我发了财之后,我发现这是使用localhost和不在xhr请求上设置usecdentials的组合。localhost让我大吃一惊,你必须使用完全限定的127.0.0.1,更令人头痛的是,http文件是在不同的端口上提供的,因此必须更改通配符以反映这一点

所以


我曾经有过这样的问题

ps:以下所有代码均由以下人员提供:

刚开始使用passport:

基本上我只是: express.js

// CookieParser should be above session
app.use(cookieParser());

// Express MongoDB session storage
app.use(session({
    saveUninitialized: true,
    resave: true,
    secret: config.sessionSecret,
    store: new mongoStore({
        db: db.connection.db,
        collection: config.sessionCollection
    })
}));

app.use( function (req, res, next) {
    if ( req.method === 'POST' && (req.url === '/auth/signin'||req.url === '/auth/login') ) {
      if ( req.body.rememberme ) {
        req.session.cookie.maxAge = 2592000000; // 30*24*60*60*1000 Rememeber 'me' for 30 days
      } else {
        req.session.cookie.expires = false;
      }
    }
    next();
  });

// use passport session
app.use(passport.initialize());
app.use(passport.session());
创建passport.js

'use strict';

/**
 * Module dependencies.
  */
var passport = require('passport'),
      User = require('mongoose').model('User'),
      path = require('path'),
      config = require('./config');

   /**
   * Module init function.
   */
module.exports = function() {
     // Serialize sessions
     passport.serializeUser(function(user, done) {
            done(null, user.id);
      });

// Deserialize sessions
passport.deserializeUser(function(id, done) {
    User.findOne({
        _id: id
    }, '-salt -password', function(err, user) {
        done(err, user);
    });
});

// Initialize strategies
config.getGlobbedFiles('./config/strategies/**/*.js').forEach(function(strategy) {
    require(path.resolve(strategy))();
});
 };
在strategies文件夹中,我创建了以下文件:

本地人.js

 `
'use strict';

/**
 * Module dependencies.
 */
var passport = require('passport'),
    LocalStrategy = require('passport-local').Strategy,
    User = require('mongoose').model('User');

module.exports = function() {
    // Use local strategy
    passport.use(new LocalStrategy({
            usernameField: 'email',
            passwordField: 'password'
        },
        function(email, password, done) {
            User.findOne({
                email: email
            }).select('-__v -notes -tags').exec(function(err, user) {
                if (err) {
                    return done(err);
                }
                if (!user) {
                    return done(null, false, {
                        message: 'Unknown user or invalid password'
                    });
                }
                if (!user.authenticate(password)) {
                    return done(null, false, {
                        message: 'Unknown user or invalid password'
                    });
                }
                user.password = undefined;
                user.salt = undefined;
                user.notes = undefined;
                user.tags = [];
                return done(null, user);
            });
        }
    ));
};
最后,要登录,我只需执行以下操作:

user.auth.js

/**
 * Signin after passport authentication
 */
exports.signin = function(req, res, next) {
    console.log(req.body);
    passport.authenticate('local', function(err, user, info) {
        if (err || !user) {
            res.status(400).send(info);
        } else {
            // Remove sensitive data before login
            user.password = undefined;
            user.salt = undefined;
            user.notes = undefined;
            user.tags = [];
            user.resetPasswordToken = undefined;
            req.login(user, function(err) {
                if (err) {
                    res.status(400).send(err);
                } else {
                    res.json(user);
                }
            });
        }
    })(req, res, next);
};

我一直感觉到同样的痛苦,对我有效的解决方案类似于FlavorScope

我意识到express会话库正在服务器上创建cookie,但它没有保存在本地cookie中。响应头会说set cookie,但没有保存任何内容。当我点击另一条路径、重新登录等时,它将无法工作,也无法识别旧会话(因为客户端/浏览器没有发送lol)。这就是为什么它在每一条路线上都进行新的会话。这个问题似乎只有1.)在服务器上以某种方式设置cookie,2.)在客户端/浏览器上以某种方式设置任何get/post请求才能解决

我让我的工作没有改变到127.0.0.1。Localhost对我来说很好。我还使用了fetchapi,它专门用于设置头部。这也是为了我的开发环境。我不得不将安全标志更改为false。Localhost是http而不是https,因此如果在开发环境中安全标志为true,它将中断。还有最后一件事,当您拥有凭证时:“include”在前端,您还需要使用特定域设置cors(这里我使用我的localhost),“*”通配符域不起作用。用我的话来说,我会说凭证:“包括”只是对浏览器说“嘿,如果我们从服务器上取回一个cookie,你可以保存这个cookie”

  • 服务器

    app.use(cors({
         origin: "http://localhost:3000",
         credentials: true
      }));
    
    app.use(cors)({
    来源:“http://localhost:3000",
    凭据:正确
    }));
    
    
    使用(会话({name:“mySession”,
    机密:process.env.SESSION\u secret,
    resave:false,
    saveUninitialized:false,
    曲奇:{
    httpOnly:true,
    安全:错误,
    最大值:60000*60*24
    },
    存储:新的RedisStore({client:redisClient})
    })) 
    
  • 用于登录的客户端/浏览器,以及get请求的另一个示例

    
            fetch(
                 "http://localhost:3001/login",
                 {
                     method: "POST",
                     headers: { "Content-Type": "application/json" },
                     body: JSON.stringify({
                         email: email,
                         password: password
                     }),
                     credentials : "include"
                 }
             )
    
    
    取回(
    "http://localhost:3001/login",
    {
    方法:“张贴”,
    标题:{“内容类型”:“应用程序/json”},
    正文:JSON.stringify({
    电邮:电邮,,
    密码:密码
    }),
    凭据:“包括”
    }
    )
  • 获取请求示例,仍然需要凭据:“包括”

    
    取回(
    "http://localhost:3001/accounts",
    {
    方法:“获取”,
    标题:{“内容类型”:“应用程序/json”},
    凭据:“包括”
    }
    )
    

    两个建议:
    res.end()
    after
    res.send(row)
    是不必要的,您可能会显示更完整的代码(比如
    app.use(session(…)
    )之后发生的事情),这样我们就可以看到您发布的各种代码片段的位置以及它们的执行顺序。这两个业务片段来自路由处理程序(我已经回去并贴上了这样的标签)。我不认为在这里添加DB检索代码会有多大用处。我只是在阅读了.end()之后才尝试了.end(),有时是在.send()之后其他地方可能存在竞争条件或其他情况。我觉得我只是缺少了一大块,而cookie没有设置。我添加了其余的初始化代码,以查看我是否只是缺少了一点配置或其他库或其他内容。@FlavorScape-您是否查看了以下问题?可能不是确切的sa您有一个问题,但似乎有一些关于如何设置或不设置
    maxAge
    ,而是
    过期的信息。还可以查看配置属性
    rolling
    resave
    saveUninitialized
    。在您的情况下
    saveUninitialized
    设置为
    false
    ,似乎会使总成本降低se,由于您没有修改会话数据,您只在成功登录后编写一次。还是我错了?非常感谢您花时间编写您的问题的解决方案。这与我遇到的问题相同,您为我节省了数小时的时间和挫折。非常感谢您的导入部分
    
         app.use(session({ name: "mySession",
                  secret: process.env.SESSION_SECRET,
                     resave: false,
                     saveUninitialized: false,
                     cookie: {
                         httpOnly: true,
                         secure: false,
                         maxAge: 60000 * 60 * 24
                     },
                     store: new RedisStore({ client: redisClient })
                 }))
    
    
            fetch(
                 "http://localhost:3001/login",
                 {
                     method: "POST",
                     headers: { "Content-Type": "application/json" },
                     body: JSON.stringify({
                         email: email,
                         password: password
                     }),
                     credentials : "include"
                 }
             )
    
    <pre><code>
          fetch(
            "http://localhost:3001/accounts",
            {
                method: "GET",
                headers: {"Content-Type": "application/json"},
                credentials: "include"
            }
        )
    </pre></code>