随着互联网的快速发展,越来越多的用户需要在线管理任务流。在这个过程中,前端技术起到了关键作用。本文将介绍如何使用 Express.js 构建一个在线任务流管理系统。通过本文的学习,你将可以掌握以下技能:
- 如何运用 Express.js 框架进行开发
- 如何创建和管理任务流
- 如何实现用户的注册、登录及权限控制
Express.js 简介
Express.js 是一款流行的 Node.js Web 应用程序框架。它提供了一组强大的功能,包括路由、中间件、模板引擎等。通过使用 Express.js,开发者可以快速编写可靠的 Web 应用程序。
项目部署流程
在开始之前,我们需要确认环境已经具备 Node.js 和 MongoDB 的运行环境。
第一步:创建项目
使用命令行或者编辑器创建一个新的项目,命名为 taskflow:
mkdir taskflow cd taskflow npm init
在该项目的根目录下,在命令行中运行 npm init
命令,创建 package.json 文件。
第二步:安装 Express.js 和其他依赖
使用 npm 安装 Express.js 和其他必要的库和模块:
npm install express mongoose passport passport-local express-session body-parser bcryptjs
- express:Express.js 框架
- mongoose:MongoDB 驱动程序
- passport:身份验证中间件
- passport-local:LocalStrategy 安全策略
- express-session:会话中间件
- body-parser:解析请求体的中间件
- bcryptjs:加密算法实现库
第三步:创建服务器
在根目录下创建一个名为 app.js 的文件。这将是我们的应用程序的入口。
// javascriptcn.com 代码示例 const express = require('express') const bodyParser = require('body-parser') const passport = require('passport') const session = require('express-session') const mongoose = require('mongoose') const app = express() // Body parser middleware app.use(bodyParser.urlencoded({ extended: false })) app.use(bodyParser.json()) // Passport Config require('./config/passport')(passport) // Mongoose Connect mongoose .connect('mongodb://localhost:27017/taskflow', { useNewUrlParser: true }) .then(() => console.log('MongoDB Connected')) .catch(err => console.log(err)) // Express session app.use( session({ secret: 'secret', resave: true, saveUninitialized: true }) ) // Passport middleware app.use(passport.initialize()) app.use(passport.session()) // Routes app.use('/', require('./routes/index')) app.use('/api/users', require('./routes/users')) app.use('/api/tasks', require('./routes/tasks')) const port = process.env.PORT || 5000 app.listen(port, () => console.log(`Server running on port ${port}`))
我们首先导入了所需的模块,创建了一个 Express 实例并将中间件添加到应用程序中。接下来我们连接到 MongoDB 数据库,并配置自定义路由,最后启动 Express 程序并监听端口。
第四步:创建 MongoDB 数据库模型
在创建任务和用户模型之前,我们必须使用 npm 安装 mongoose:
npm install mongoose --save
接下来,在根目录下创建一个名为 models 的文件夹,并在该文件夹中创建两个文件:task.js 和 user.js。
// javascriptcn.com 代码示例 // task.js const mongoose = require('mongoose') const Schema = mongoose.Schema // Create Schema const TaskSchema = new Schema({ name: { type: String, required: true }, status: { type: String, default: 'created' }, user: { type: Schema.Types.ObjectId, ref: 'users' }, created_date: { type: Date, default: Date.now } }) module.exports = Task = mongoose.model('tasks', TaskSchema)
// javascriptcn.com 代码示例 // user.js const mongoose = require('mongoose') const Schema = mongoose.Schema // Create Schema const UserSchema = new Schema({ name: { type: String, required: true }, email: { type: String, required: true }, password: { type: String, required: true }, created_date: { type: Date, default: Date.now } }) module.exports = User = mongoose.model('users', UserSchema)
第五步:创建路由
我们为任务和用户创建了两个数据库模型。现在我们需要创建对 API 路由的支持。在根目录下创建一个名为 routes 的文件夹,并在该文件夹中创建三个文件:
- index.js - 首页路由
- tasks.js - 任务路由
- users.js - 用户路由
// javascriptcn.com 代码示例 // index.js const express = require('express') const router = express.Router() router.get('/', (req, res) => { res.json({ msg: 'Welcome to TaskFlow' }) }) module.exports = router
// javascriptcn.com 代码示例 // users.js const express = require('express') const router = express.Router() const bcrypt = require('bcryptjs') const passport = require('passport') const jwt = require('jsonwebtoken') // Load User model const User = require('../models/User') // Register router.post('/register', (req, res) => { const { name, email, password } = req.body User.findOne({ email: email }).then(user => { if (user) { return res.status(400).json({ email: 'Email already exists' }) } const newUser = new User({ name, email, password }) bcrypt.genSalt(10, (err, salt) => { bcrypt.hash(newUser.password, salt, (err, hash) => { if (err) throw err newUser.password = hash newUser .save() .then(user => { res.json(user) }) .catch(err => console.log(err)) }) }) }) }) // Login router.post('/login', (req, res, next) => { passport.authenticate('local', { failureFlash: true }, (err, user, info) => { if (err) { return next(err) } if (!user) { return res.status(401).json(info) } req.logIn(user, err => { if (err) { return next(err) } const token = jwt.sign( { userId: user._id, userName: user.name }, 'secret', { expiresIn: '24h' } ) return res.json({ token }) }) })(req, res, next) }) module.exports = router
// javascriptcn.com 代码示例 // tasks.js const express = require('express') const router = express.Router() const User = require('../models/User') const Task = require('../models/Task') const passport = require('passport') const jwt = require('jsonwebtoken') router.get('/', passport.authenticate('jwt', { session: false }), (req, res) => { Task.find({ user: req.user._id }) .sort({ created_date: -1 }) .then(tasks => res.json(tasks)) .catch(err => console.log(err)) }) router.post('/', passport.authenticate('jwt', { session: false }), (req, res) => { const { name } = req.body const newTask = new Task({ name, user: req.user._id }) newTask .save() .then(task => res.json(task)) .catch(err => console.log(err)) }) router.put('/:id', passport.authenticate('jwt', { session: false }), (req, res) => { Task.findByIdAndUpdate( { _id: req.params.id }, { $set: req.body }, { new: true } ).then(task => res.json(task)) }) router.delete('/:id', passport.authenticate('jwt', { session: false }), (req, res) => { Task.findById(req.params.id) .then(task => task .remove() .then(() => res.json({ success: true })) .catch(err => res.status(404).json({ success: false })) ) .catch(err => res.status(404).json({ success: false })) }) module.exports = router
在这些文件中,我们分别定义了对应的 RESTful API 接口,提供了任务的基本操作。其中,用户模型被添加到 user.js 文件中,任务模型被添加到 task.js 文件中。想要查找任务,用户必须先登录。因此,任务路由的每个请求都需要进行身份验证。
第六步:实现安全控制
为了提高系统的安全性,我们需要实现以下几点:
- 用户必须进行身份验证才能登陆系统
- 用户必须要进行角色认证才能进行操作
我们可以通过使用 Passport.js、bcrypt.js 和 JSON Web Token (JWT) 来实现身份验证和权限控制。
在路由文件夹中创建 passport.js 文件:
// javascriptcn.com 代码示例 const LocalStrategy = require('passport-local').Strategy const bcrypt = require('bcryptjs') const User = require('../models/User') module.exports = function(passport) { passport.use( new LocalStrategy({ usernameField: 'email' }, (email, password, done) => { // Match user User.findOne({ email: email }) .then(user => { if (!user) { return done(null, false, { message: 'Email not found' }) } // Match password bcrypt.compare(password, user.password, (err, isMatch) => { if (err) throw err if (isMatch) { return done(null, user) } else { return done(null, false, { message: 'Password incorrect' }) } }) }) .catch(err => console.log(err)) }) ) passport.serializeUser((user, done) => { done(null, user.id) }) passport.deserializeUser((id, done) => { User.findById(id, (err, user) => { done(err, user) }) }) }
在这里,我们使用 LocalStrategy 进行身份验证。该方法检查用户输入的邮箱和密码是否正确。通过 bcrypt.compare() 方法判断密码是否匹配。serializeUser 和 deserializeUser 方法将用户信息保存在会话中。
我们还需要创建一个名为 passport.js 的文件,使用 jsonwebtoken 来为用户签名:
// javascriptcn.com 代码示例 const jwtStrategy = require('passport-jwt').Strategy const extractJwt = require('passport-jwt').ExtractJwt const mongoose = require('mongoose') const User = mongoose.model('users') const opts = {} opts.jwtFromRequest = extractJwt.fromAuthHeaderAsBearerToken() opts.secretOrKey = 'secret' module.exports = passport => { passport.use( new jwtStrategy(opts, (jwt_payload, done) => { User.findOne({ _id: jwt_payload.userId }) .then(user => { if (user) { return done(null, user) } return done(null, false) }) .catch(err => console.log(err)) }) ) }
该文件实现了 JWT 签名过程。在此示例中,我们使用了 secret 作为密钥,把用户ID 和姓名加密输出。
接下来,将上述三个文件引入到 app.js 文件中。
// Passport Config require('./config/passport')(passport) // Routes app.use('/', require('./routes/index')) app.use('/api/users', require('./routes/users')) app.use('/api/tasks', require('./routes/tasks'))
第七步:建立前端交互
接下来我们开始构建前端。在我的项目中,我使用了 React.js 和 Ant Design 来建立前端交互。因为这部分代码比较庞大,就不在这里赘述了。
总结
在本文中,我们演示了如何使用 Express.js 、MongoDB 和 Passport.js 构建一个在线的任务流管理系统。我们实现了用户注册、用户登录、任务创建、任务查看、任务编辑和任务删除等功能。本文提供的代码可以让开发人员更快的了解和掌握基于 Express.js 构建应用程序的过程。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6528e8ad7d4982a6ebb76299