使用 Passport.js、express-session 和 express-mysql-session 进行用户身份验证

Posted

技术标签:

【中文标题】使用 Passport.js、express-session 和 express-mysql-session 进行用户身份验证【英文标题】:User authentication using Passport.js, express-session and express-mysql-session 【发布时间】:2018-10-21 20:13:17 【问题描述】:

我正在尝试使用 Node.js、Express、Passport.js 和 mysql 数据库创建用户身份验证。我能够注册用户(从代码中排除,以便于阅读)并且我能够登录(我从护照获得 succesRedirect) - 但我无法序列化用户并且我很确定我的会话有问题。

当我运行我的代码时,我收到以下错误:

错误:无法将用户序列化到会话中

这是我的代码:

var express             = require('express'),
    app                 = express(),
    bodyParser          = require('body-parser'),
    mysql               = require('mysql'),
    generator           = require('generate-password'),
    cookieParser        = require('cookie-parser'),
    expressValidator    = require('express-validator'),
    session             = require('express-session'),
    passport            = require('passport'),
    MySQLStore          = require('express-mysql-session')(session),
    LocalStrategy       = require('passport-local').Strategy,
    bcrypt              = require('bcrypt');

const saltRounds = 10;

app.set("view engine", "ejs");
app.use(express.static(__dirname + "/public"));
app.use(bodyParser.urlencoded(extended: true));
app.use(expressValidator());
app.use(cookieParser());
var options = 
   host     : 'localhost',
   user     : 'MY-USER',
   database : "c9",
   password : "",
   multipleStatements: true
;

var sessionStore = new MySQLStore(options);

app.use(session(
   secret: 'dfsfjdssdvsdvawdslepsv',
   resave: true,
   store: sessionStore,
   saveUninitialized: true
));

app.use(passport.initialize()); 
app.use(passport.session());

//Start MYSQL database
var connection = mysql.createConnection(
   host     : 'localhost',
   user     : 'MY-USER',
   database : "c9",
   password : "",
   multipleStatements: true
);
connection.connect(function(err)
    if(!err) 
        console.log("Database is connected ...");
     else 
        console.log("Error connecting database ...");
    
);

app.get("/", isAuthenticated, function(req, res, next)
    res.render('dashboard');
);

//show login form
app.get("/login", function(req, res)
    res.render("login");
);

//login
app.post("/login", passport.authenticate(
    'local', 
        successRedirect: '/',
        failureRedirect: '/login'
));

//create new user
app.post("/users", function(req, res)
    var today = new Date();
    //generate password + salt
    var password = generator.generate(
                length: 8,
                numbers: true,
                symbols: false
    );
    var salt = bcrypt.genSaltSync(saltRounds);
    var hash = bcrypt.hashSync(password, salt);
    console.log(salt);
            
    //create user object
    var user = 
        first_name  : req.body.first_name,
        last_name   : req.body.last_name,
        email       : req.body.email,
        password    : hash,
        salt        : salt,
        created     : today,
        modified    : today,
        user_role   : req.body.user_role
    ;

    //check if email already exists in database
    connection.query('SELECT email FROM users WHERE email=?', user.email, function(error, results, fields)
        if(error) 
            throw error;
        
        if(results.length > 0) 
            //email already exists in database
            res.redirect("/");
            return;
         else 
            //email does not exist from before
            //add user to database
            connection.query('INSERT INTO users SET ?', user, function(err, result) 
            if(err) throw err;
            
            connection.query('SELECT LAST_INSERT_ID() as user_id', function(error, results, fields)
               if(error) throw error;
               
            );
            
            //Send registration email
            res.redirect("users");
            );
        
    );
);

passport.serializeUser(function(user, done)
    done(null, user.id);
);

passport.deserializeUser(function(id, done)
    connection.query('SELECT * FROM users WHERE id = ?', id, function (err, rows)
        done(err, rows[0]);
    );
);

//Authenticate users
passport.use(new LocalStrategy(
    function(username, password, done) 
        connection.query('SELECT password, salt FROM users WHERE email = ?', [username], function(err, results, fields)
            //DB error
            if(err) done(err);
            
            //no user was found
            if(results.length === 0) 
                done(null, false);
            
            
            var salt = results[0].salt;
            if(bcrypt.hashSync(password, salt) === results[0].password) 
                //Success
                return done(null, true);
             else 
                //Wrong password
                return done(null, false);
            
        );
    
));

function isAuthenticated(req, res, next) 
    if (req.isAuthenticated())
        return next();
    res.redirect('/login');


app.listen(process.env.PORT, process.env.IP, function()
    console.log("Server started...");
);

在我看来,我正在做的正是我从不同的教程和文档中读到的东西。谁能看到我失败的地方?

用户数据库如下所示:

CREATE TABLE `users` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `first_name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
 `last_name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
 `email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
 `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `salt` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `created` datetime NOT NULL,
 `modified` datetime NOT NULL,
 `user_role` varchar(100) NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

会话数据库如下所示:

CREATE TABLE IF NOT EXISTS `sessions` ( 
`session_id` varchar(128) COLLATE utf8mb4_bin NOT NULL, 
`expires` int(11) unsigned NOT NULL, 
`data` text COLLATE utf8mb4_bin, 
PRIMARY KEY (`session_id`) 
) ENGINE=InnoDB

【问题讨论】:

【参考方案1】:

发现问题。

passport.serializeUser(function(user, done)
    done(null, user.id);
);

应该获取并发送一个用户 ID。在我的代码中,它需要一个用户。

现在解决了!

【讨论】:

以上是关于使用 Passport.js、express-session 和 express-mysql-session 进行用户身份验证的主要内容,如果未能解决你的问题,请参考以下文章

为啥除了 passport.js 还要使用 cookie-session?

如何在 passport-facebook / Passport.js 中捕获 FacebookAuthorizationError?

格兰特 vs Passport.js? [关闭]

如何使用 Passport.js 访问 Cookie 集

仍然需要使用带有 passport.js 的 cookie-parser 吗?

使用 Passport.js 和 Sails.js 注册后如何重定向到特定位置?