4.8.1 登出

现在我们来完成登出的功能。修改 routes/signout.js 如下:

routes/signout.js

  1. const express = require('express')
  2. const router = express.Router()
  3. const checkLogin = require('../middlewares/check').checkLogin
  4. // GET /signout 登出
  5. router.get('/', checkLogin, function (req, res, next) {
  6. // 清空 session 中用户信息
  7. req.session.user = null
  8. req.flash('success', '登出成功')
  9. // 登出成功后跳转到主页
  10. res.redirect('/posts')
  11. })
  12. module.exports = router

此时刷新页面,点击右上角的 登出,成功后如下图所示:

登出与登录 - 图1

4.8.2 登录页

现在我们来完成登录页。修改 routes/signin.js 相应代码如下:

routes/signin.js

  1. router.get('/', checkNotLogin, function (req, res, next) {
  2. res.render('signin')
  3. })

新建 views/signin.ejs,添加如下代码:

views/signin.ejs

  1. <%- include('header') %>
  2. <div class="ui grid">
  3. <div class="four wide column"></div>
  4. <div class="eight wide column">
  5. <form class="ui form segment" method="post">
  6. <div class="field required">
  7. <label>用户名</label>
  8. <input placeholder="用户名" type="text" name="name">
  9. </div>
  10. <div class="field required">
  11. <label>密码</label>
  12. <input placeholder="密码" type="password" name="password">
  13. </div>
  14. <input type="submit" class="ui button fluid" value="登录">
  15. </form>
  16. </div>
  17. </div>
  18. <%- include('footer') %>

现在刷新页面,点击右边上角 登录 试试吧,我们已经看到了登录页,但先不要点击登录,接下来我们实现处理登录的逻辑。

4.8.3 登录

现在我们来完成登录的功能。修改 models/users.js 添加 getUserByName 方法用于通过用户名获取用户信息:

models/users.js

  1. const User = require('../lib/mongo').User
  2. module.exports = {
  3. // 注册一个用户
  4. create: function create (user) {
  5. return User.create(user).exec()
  6. },
  7. // 通过用户名获取用户信息
  8. getUserByName: function getUserByName (name) {
  9. return User
  10. .findOne({ name: name })
  11. .addCreatedAt()
  12. .exec()
  13. }
  14. }

这里我们使用了 addCreatedAt 自定义插件(通过 _id 生成时间戳),修改 lib/mongo.js,添加如下代码:

lib/mongo.js

  1. const moment = require('moment')
  2. const objectIdToTimestamp = require('objectid-to-timestamp')
  3. // 根据 id 生成创建时间 created_at
  4. mongolass.plugin('addCreatedAt', {
  5. afterFind: function (results) {
  6. results.forEach(function (item) {
  7. item.created_at = moment(objectIdToTimestamp(item._id)).format('YYYY-MM-DD HH:mm')
  8. })
  9. return results
  10. },
  11. afterFindOne: function (result) {
  12. if (result) {
  13. result.created_at = moment(objectIdToTimestamp(result._id)).format('YYYY-MM-DD HH:mm')
  14. }
  15. return result
  16. }
  17. })

小提示:24 位长的 ObjectId 前 4 个字节是精确到秒的时间戳,所以我们没有额外的存创建时间(如: createdAt)的字段。ObjectId 生成规则:

登出与登录 - 图2

修改 routes/signin.js 如下:

routes/signin.js

  1. const sha1 = require('sha1')
  2. const express = require('express')
  3. const router = express.Router()
  4. const UserModel = require('../models/users')
  5. const checkNotLogin = require('../middlewares/check').checkNotLogin
  6. // GET /signin 登录页
  7. router.get('/', checkNotLogin, function (req, res, next) {
  8. res.render('signin')
  9. })
  10. // POST /signin 用户登录
  11. router.post('/', checkNotLogin, function (req, res, next) {
  12. const name = req.fields.name
  13. const password = req.fields.password
  14. // 校验参数
  15. try {
  16. if (!name.length) {
  17. throw new Error('请填写用户名')
  18. }
  19. if (!password.length) {
  20. throw new Error('请填写密码')
  21. }
  22. } catch (e) {
  23. req.flash('error', e.message)
  24. return res.redirect('back')
  25. }
  26. UserModel.getUserByName(name)
  27. .then(function (user) {
  28. if (!user) {
  29. req.flash('error', '用户不存在')
  30. return res.redirect('back')
  31. }
  32. // 检查密码是否匹配
  33. if (sha1(password) !== user.password) {
  34. req.flash('error', '用户名或密码错误')
  35. return res.redirect('back')
  36. }
  37. req.flash('success', '登录成功')
  38. // 用户信息写入 session
  39. delete user.password
  40. req.session.user = user
  41. // 跳转到主页
  42. res.redirect('/posts')
  43. })
  44. .catch(next)
  45. })
  46. module.exports = router

这里我们在 POST /signin 的路由处理函数中,通过传上来的 name 去数据库中找到对应用户,校验传上来的密码是否跟数据库中的一致。不一致则返回上一页(即登录页)并显示『用户名或密码错误』的通知,一致则将用户信息写入 session,跳转到主页并显示『登录成功』的通知。

现在刷新页面,点击右上角 登录,用刚才注册的账号登录,如下图所示:

登出与登录 - 图3