介绍
就像身份验证在API中很重要一样,它也是某些Web应用程序中的重要功能-那些页面和机密仅应由注册和身份验证的用户访问。
在本教程中,您将在学习如何创建用户注册的同时构建一个简单的Web应用程序。
应用程式设定
在您将要工作的地方创建一个新目录。 为了本教程的缘故,我将其称为mine site-auth 。 在刚创建的新目录中初始化npm。 这是初始化npm的方法。
npm init -y
-y
标志告诉npm使用默认选项。
编辑package.json文件的依赖项部分,使其看起来像我的一样。
#package.json
{
"name": "site-auth",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "izuchukwu1",
"license": "ISC",
"dependencies": {
"bcryptjs": "^2.4.3",
"body-parser": "^1.17.1",
"connect-flash": "^0.1.1",
"cookie-parser": "^1.4.3",
"express": "^4.15.2",
"express-handlebars": "^3.0.0",
"express-messages": "^1.0.1",
"express-session": "^1.15.2",
"joi": "^13.0.1",
"mongoose": "^4.11.12",
"morgan": "^1.8.1",
"passport": "^0.4.0",
"passport-local": "^1.0.0"
}
}
完成后,运行命令以安装依赖项。
npm install
在工作目录中创建一个名为app.js的文件。
首先需要安装的依赖项和必要的文件。
#app.js
const express = require('express');
const morgan = require('morgan')
const path = require('path');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const expressHandlebars = require('express-handlebars');
const flash = require('connect-flash');
const session = require('express-session');
const mongoose = require('mongoose')
const passport = require('passport')
require('./config/passport')
这些依赖项是在您运行npm install时安装的。 要在您的应用程序中使用它们,您必须要求它们并将它们保存在各自的常量中。
对于本教程,您将使用MongoDB作为数据库。 您将需要在数据库中存储用户信息。 要使用MongoDB,您将使用Mongoose(一种用于Node.js的MongoDB建模工具)。 这样,设置猫鼬很容易。
#app.js
mongoose.Promise = global.Promise
mongoose.connect('mongodb://localhost:27017/site-auth')
至此,让我们设置中间件。
// 1
const app = express()
app.use(morgan('dev'))
// 2
app.set('views', path.join(__dirname, 'views'))
app.engine('handlebars', expressHandlebars({ defaultLayout: 'layout' }))
app.set('view engine', 'handlebars')
// 3
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(express.static(path.join(__dirname, 'public')))
app.use(session({
cookie: { maxAge: 60000 },
secret: 'codeworkrsecret',
saveUninitialized: false,
resave: false
}));
app.use(passport.initialize())
app.use(passport.session())
// 4
app.use(flash())
app.use((req, res, next) => {
res.locals.success_mesages = req.flash('success')
res.locals.error_messages = req.flash('error')
next()
})
// 5
app.use('/', require('./routes/index'))
app.use('/users', require('./routes/users'))
// 6
// catch 404 and forward to error handler
app.use((req, res, next) => {
res.render('notFound')
});
// 7
app.listen(5000, () => console.log('Server started listening on port 5000!'))
- Express已初始化并分配给
app
。 - 设置了用于处理视图的中间件。 对于视图,您将使用
handlebars
。 - 您设置了用于
bodyparser
,cookie
,session
和passport
中间件。 用户要登录时将使用Passport。 - 在某些时候,您将显示即时消息。 因此,您需要为此设置中间件,并创建所需的Flash消息类型。
- 路由中间件-这将处理对URL路径的任何请求。 此处指定的URL路径用于索引和用户路径。
- 处理404错误的中间件。 当请求未映射到在其上方创建的任何中间件时,该中间件即会启动。
- 服务器设置为侦听端口5000。
视图设置
创建一个名为views的新目录。 在views目录中,创建另外两个目录,称为layouts和partials 。 您希望在视图中实现这样的树结构,因此请在它们各自的目录中创建必要的文件。
├── dashboard.handlebars
├── index.handlebars
├── layouts
│ └── layout.handlebars
├── login.handlebars
├── notFound.handlebars
├── partials
│ └── navbar.handlebars
└── register.handlebars
完成后,是时候删除代码了。
#dashboard.handlebars
User DashBoard
这是一个仪表板,仅对注册用户可见。 对于本教程,这将是您的秘密页面。
现在,应用程序的索引页面应如下所示。
#index.handlebars
Site Authentication!
Welcome aboard.
该应用程序需要一个将要使用的布局,这就是您将要使用的布局。
#layout/layout.handlebars
Site Authentication
{{#if success_messages }}
{{success_messages}}
{{/if}}
{{#if error_messages }}
{{error_messages}}
{{/if}}
{{> navbar}}
{{{body}}}
您需要注册用户的登录页面。
#views/login.handlebars
notFound .handlebars文件将用作您的错误页面。
#views/notFound.handlebars
Error
您的注册页面应该看起来像这样。
最后,对于您的意见,这里是您的导航栏。
#partials/navbar.handlebars
Site Authentication
完成此操作后,您很高兴深入了解某些部分。
资料验证
您将需要一个用户模型。 从上面的视图代码中,您可以推断出用户模型所需的属性是电子邮件,用户名和密码。 创建一个名为models的目录,并在其中创建一个名为user.js的文件。
#models/user.js
// 1
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const bcrypt = require('bcryptjs')
// 2
const userSchema = new Schema({
email: String,
username: String,
password: String
}, {
// 3
timestamps: {
createdAt: 'createdAt',
updatedAt: 'updatedAt'
}
})
// 4
const User = mongoose.model('user', userSchema)
module.exports = User
- 导入依赖项并将其保存为常量。
- 创建一个新的架构。 对于每个用户,您要将
email
,username
和password
保存到数据库中。 该模式显示了如何为每个文档构造模型。 在这里,您希望电子邮件,用户名和密码为字符串类型。 - 对于保存到数据库的每个用户,您还希望创建
timestamps
。 你利用猫鼬获得createdAt
和updatedAt
,然后将此保存到数据库中。 - 定义模型并将其分配给名为
User
的常量,然后将其导出为模块,以便可以在应用程序的其他部分中使用。
密码的盐化和散列
您不想将用户密码存储为纯文本。 这是用户在注册时输入纯文本密码时要执行的操作。 纯文本密码应使用由您的应用程序生成的盐(使用bcryptjs)进行哈希处理。 该哈希密码然后存储在数据库中。
听起来不错吧? 让我们在user.js文件中实现它。
#models/user.js
module.exports.hashPassword = async (password) => {
try {
const salt = await bcrypt.genSalt(10)
return await bcrypt.hash(password, salt)
} catch(error) {
throw new Error('Hashing failed', error)
}
}
您刚刚创建了一个在用户注册事件中将被调用的方法。 该方法将接收用户输入的纯文本密码。 如前所述,纯文本密码将使用生成的盐进行哈希处理。 哈希密码将作为用户密码返回。
索引和用户路线
创建一个名为路由的新目录。 在这个新目录中,创建两个新文件: index.js和users.js 。
index.js文件将非常简单。 它将映射到您的应用程序的索引。 请记住,执行此操作时,您在app.js文件中为路由设置了中间件。
app.use('/', require('./routes/index'))
app.use('/users', require('./routes/users'))
因此,仅呈现索引页面的索引路由应如下所示。
#routes/index.js
const express = require('express')
const router = express.Router()
router.get('/', (req, res) => {
res.render('index')
})
module.exports = router
现在向用户路由。 目前,此路由文件将执行四项操作。
- 需要依赖项。 您将需要使用NPM安装的依赖项。
- 验证用户输入。 您要确保用户未提交空白表格。 所有输入都是必需的,并且所有输入都必须为String类型。 电子邮件具有称为
.email()
的特殊验证,可确保输入的内容与电子邮件格式匹配,同时使用正则表达式验证密码。 对于确认密码,您希望它与输入的密码相同。 这些验证是使用Joi完成的。 - 设置您的路由器。 GET请求呈现注册页面,而POST请求在用户单击按钮提交表单时启动。
- 路由器将作为模块导出。
代码如下所示。
#routes/users.js
const express = require('express');
const router = express.Router()
const Joi = require('joi')
const passport = require('passport')
const User = require('../models/user')
//validation schema
const userSchema = Joi.object().keys({
email: Joi.string().email().required(),
username: Joi.string().required(),
password: Joi.string().regex(/^[a-zA-Z0-9]{6,30}$/).required(),
confirmationPassword: Joi.any().valid(Joi.ref('password')).required()
})
router.route('/register')
.get((req, res) => {
res.render('register')
})
.post(async (req, res, next) => {
try {
const result = Joi.validate(req.body, userSchema)
if (result.error) {
req.flash('error', 'Data entered is not valid. Please try again.')
res.redirect('/users/register')
return
}
const user = await User.findOne({ 'email': result.value.email })
if (user) {
req.flash('error', 'Email is already in use.')
res.redirect('/users/register')
return
}
const hash = await User.hashPassword(result.value.password)
delete result.value.confirmationPassword
result.value.password = hash
const newUser = await new User(result.value)
await newUser.save()
req.flash('success', 'Registration successfully, go ahead and login.')
res.redirect('/users/login')
} catch(error) {
next(error)
}
})
module.exports = router
让我们更深入地了解该POST请求中发生的情况。
可通过req.body
访问在注册表中输入的值,这些值看起来像这样。
value:
{ email: '[email protected]',
username: 'izu',
password: 'chinedu',
confirmationPassword: 'chinedu' },
使用上面创建的userSchema
对此进行验证,并将用户输入的值分配给一个名为result的常量。
如果由于验证遇到错误,则会向用户显示错误消息,并重定向到注册页面。
否则,我们尝试查找是否存在具有相同电子邮件地址的用户,因为您不希望有两个或多个具有相同电子邮件地址的用户。 如果找到用户,则告知用户该电子邮件地址已被使用。
在没有注册用户拥有该电子邮件地址的情况下,下一步是对密码进行哈希处理。 在这里,您可以调用在user.js文件中创建的hashPassword
方法。 新的哈希密码分配给一个称为哈希的常量。
无需将confirmationPassword
存储在数据库中。 因此,将其删除。 结果可用的密码仍然是普通密码。 由于您不想在数据库中存储普通密码,因此将密码值重新分配给创建的哈希值很重要。 这是用一行代码完成的。
result.value.password = hash
新的用户实例将保存到数据库。 将显示一条简短消息,指示注册成功,并且用户被重定向到登录页面。
通过运行以下命令从终端启动服务器:
node app.js
将浏览器指向http:// localhost:5000 ,您应该会看到新应用。
结论
现在,您知道如何在Node Web应用程序中实现注册功能。 您已经了解了验证用户输入的重要性以及如何使用Joi进行验证。 您还使用了bcryptjs
对密码进行加密和哈希处理。
接下来,您将看到如何为注册用户实施登录功能。 我相信你很开心!
翻译自: https://code.tutsplus.com/tutorials/site-authentication-in-nodejs-user-sign-up--cms-29933