node.js - 如何在带有 sqlite 数据库的 nodejs 上使用 passport.js
问题描述
您好我对nodejs很陌生,这是我的第一个问题。我想将用户登录添加到我的快速服务器。所以我尝试了 passport.js 示例(express-4.x-local-example)。现在我尝试将用户存储在我的 sqlite 数据库中。我针对其他问题(使用 sqlite 的 node.js 护照认证)。但这并没有解决我的问题。我不想用它创建一个实时应用程序,我只想了解它是如何工作的。当我将用户添加到我的数据库并尝试登录时,我总是被定向到 /bad。
这是我写的代码:
数据库.js
const sqlite3 = require("sqlite3");
const sqlite = require("sqlite");
const fs = require("fs").promises;
async function provideDatabase() {
const databaseExists = await fs
.access("./.data/database.db")
.catch(() => false);
const db = await sqlite.open({
filename: "./.data/database.db",
driver: sqlite3.Database
});
if (databaseExists === false) {
await db.exec(
"CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT, password TEXT, salt TEXT)"
);
}
return db;
}
module.exports = provideDatabase;
这是我的 server.js
var express = require('express');
var passport = require('passport');
var Strategy = require('passport-local').Strategy;
const provideDatabase = require("./database");
const database = provideDatabase();
const LocalStrategy = require('passport-local').Strategy
const bodyParser = require("body-parser");
var app = express();
app.use(bodyParser.json());
var crypto = require('crypto');
function hashPassword(password, salt) {
var hash = crypto.createHash('sha256');
hash.update(password);
hash.update(salt);
return hash.digest('hex');
}
passport.use(new LocalStrategy(async function(username, password, done) {
const db = await database;
db.get('SELECT salt FROM users WHERE username = ?', username, function(err, row) {
if (!row) return done(null, false);
var hash = hashPassword(password, row.salt);
db.get('SELECT username, id FROM users WHERE username = ? AND password = ?', username, hash, function(err, row) {
if (!row) return done(null, false);
return done(null, row);
});
});
}));
passport.serializeUser(function(user, done) {
return done(null, user.id);
});
passport.deserializeUser(async function(id, done) {
const db = await database;
db.get('SELECT id, username FROM users WHERE id = ?', id, function(err, row) {
if (!row) return done(null, false);
return done(null, row);
});
});
app.post('/login', passport.authenticate('local', { successRedirect: '/good',
failureRedirect: '/bad' }));
// Configure view engine to render EJS templates.
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
// Define routes.
app.get('/',
function(req, res) {
res.render('home', { user: req.user });
});
app.get('/login',
function(req, res){
res.render('login');
});
app.get('/logout',
function(req, res){
req.logout();
res.redirect('/');
});
app.get('/profile',
require('connect-ensure-login').ensureLoggedIn(),
function(req, res){
res.render('profile', { user: req.user });
});
app.get("/user", async (request, response) => {
const db = await database;
const results = await db.all("SELECT * FROM users");
response.send(results);
});
app.post("/user", async (request, response) => {
const db = await database;
hashedPassword = hashPassword(request.body.password, request.body.salt)
const created = await db.run(
"INSERT INTO users (username, password, salt) VALUES(?,?,?)",
request.body.username,
hashedPassword,
request.body.salt
);
const user = await db.get("SELECT * FROM users WHERE Id = ?", [
created.lastID
]);
response.status(201).send(user);
});
app.listen(3000);
解决方案
我正在从生产项目中获取我的代码。虽然没有使用 SQLite,但概念应该是一样的。
我使用bcrypt
而不是实现我自己的加密。我建议您也这样做,以避免在误用的情况下出现错误和安全问题。
我还将护照逻辑放在一个单独的文件中,以使代码看起来更清晰并避免混淆。
// Dependencies
const passport = require('passport');
const { Strategy: LocalStrategy, } = require('passport-local');
const bcrypt = require('bcrypt');
// Load model for User_DB
const { User_DB, } = require('../dataBase/dbConnection');
// Winston Logger
const passLog = require('../system/log').get('passportLog');
// Session
// Take in user id => keep the session data small
passport.serializeUser((id, done) => {
done(null, id);
});
// Deserialize when needed by querying the DB for full user details
passport.deserializeUser(async (id, done) => {
try {
const user = await User_DB.findById(id);
done(null, user);
} catch (err) {
passLog.error(`Error Deserializing User: ${id}: ${err}`);
}
});
// Export the passport module
module.exports = (passport) => {
passport.use(new LocalStrategy({ usernameField: 'email', }, async (email, password, done) => {
try {
// Lookup the user
const userData = await User_DB.findOne({ email: email, }, {
password: 1, }); // Return the password hash only instead of the whole user object
// If the user does not exist
if (!userData) {
return done(null, false);
}
// Hash the password and compare it to the hash in the database
const passMatch = await bcrypt.compare(password, userData.password);
// If the password hash does not match
if (!passMatch) {
return done(null, false);
}
// Otherwise return the user id
return done(null, userData.id);
} catch (err) {
passLog.error(`Login Error: ${err}`);
}
}));
};
这些护照选项似乎经常出现故障或表现出奇怪的行为,因此我建议您像在我的控制器中一样处理重定向逻辑。
{ successRedirect: '/good',
failureRedirect: '/bad' }
登录控制器逻辑:(我在这里省略了用于会话存储的代码并进行了一些修改,但此代码应该可以满足您的需要)
const login = (req, res, next) => {
//Using passport-local
passport.authenticate('local', async (err, user) => {
//If user object does not exist => login failed
if (!user) { return res.redirect('/unauthorized'); }
//If all good, log the dude in
req.logIn(user, (err) => {
if (err) { return res.status(401).json({ msg: 'Login Error', }); }
// Send response to the frontend
return res.redirect('/good');
});
});
})(req, res, next);
};
实际路线:
// Import the controller
const {login} = require('../controllers/auth');
// Use it in the route
router.post('/auth/login', login);
推荐阅读
- jquery - 在循环内更改多个下拉列表值
- laravel - 将 laravel 表单更改为 html 表单
- angular - 如何使用 ng2-stompjs 向许多订阅者广播消息?
- google-cloud-messaging - 在 GCM 弃用后,我能否获得新的 GCM 令牌?
- pytorch - 我不明白在 pytorch 中训练分类器的代码
- python - 不可散列的类型:字典中的“列表”
- html - 如何自动/有效地将我的 minecraft 服务器的banned-players.json 实现为 html?
- python - 为什么我过滤时 pandas 不能正确读取数据?
- python-2.7 - 我必须删除 Python 数据框中列中的最后一个数字和字符?
- kubernetes - 管理 Kubernetes 清单更改的正确方法是什么?