前端

17. Node.js 项目的登录登出功能

2019-04-25  本文已影响14人  璎珞纨澜

本项目基于 node.js 的 express 框架,数据库使用 mongoDB

步骤

  1. 初始化 package.json:
    项目目录下执行命令 npm init -y
  2. 创建 git 仓库:
    项目目录执行命令 git init
  3. 新建项目说明文件 README.md
  4. 安装项目核心包 express 与 mongoose
  5. 配置模板引擎 express-art-template
  6. 创建 Views 目录以存放 html 页面文件
  7. 安装 bootstrap 和 jquery
  8. 提取路由模块并设计路由
  9. 设计用户数据 Schema
  10. 处理注册页面:
    10.1 配置解析表单 POST 请求体插件 body-parser
    10.2 配置密码加密插件 blueimp-md5
    10.3 配置 express-session 插件,通过 session 保存登录状态
  11. 处理登录页面
  12. 处理退出页面

路由设计

路径 方法 get 参数 post 参数 是否需要登陆 功能
/ GET 渲染首页
/register GET 渲染注册页面
/register POST email、nickname、password 处理注册请求
/login GET 渲染登录页面
/login POST email、password 处理登录请求
/logout GET 处理退出请求

表单的同步提交和异步提交

同步提交与优化:
表单具有默认提交行为,默认是同步的。同步表单提交,浏览器会锁死(转圈儿)等待服务端的响应结果。表单同步提交后,无论服务端响应的是什么,浏览器都会把响应的结果直接渲染到当前容器中,覆盖掉当前页面。这种交互方式给人不好的用户体验。为了避免这种不好的交互体验,可以对当前页面进行重新渲染。
(场景:用户注册时提示邮箱或密码已存在)

router.post('/register', function (req, res) {
  // 1. 获取表单提交的数据 req.body  ...省略代码...
  // 2. 查询数据库判断该用户是否存在 ...省略代码...
  // 3. 存在则得到查询结果 data
    if (data) {
    // 4. 响应结果
    return res.render('register.html', {
    err_message: '邮箱或密码已存在', // 回复后用于浏览器将报错信息渲染到页面
    form: req.body  // 回复后用于浏览器将用户信息渲染到页面
    })
})
<!--渲染 err_message-->
<p>{{ err_message }}</p>
<!--表单提交的默认行为是发送 url 为 /register 的post请求-->
<form id="register_form" method="post" action="/register">
      <div class="form-group">
        <label for="email">邮箱</label>
        <input type="email" class="form-control" id="email" name="email" placeholder="Email" autofocus value="{{ form && form.email }}">
      </div>
      <div class="form-group">
        <label for="nickname">昵称</label>
        <input type="text" class="form-control" id="nickname" name="nickname" placeholder="Nickname" value="{{ form && form.nickname }}">
      </div>
      <div class="form-group">
        <label for="password">密码</label>
        <input type="password" class="form-control" id="password" name="password" placeholder="Password">
      </div>
      <button type="submit" class="btn btn-success btn-block">注册</button>
    </form>

异步提交:
ajax 等异步交互方式诞生后,表单就可以通过 ajax 进行异步提交了。异步表单提交,浏览器不会等待服务端的响应结果,也不会再有响应结果返回后覆盖掉当前页面的糟糕交互体验了。但需要注意的是,同步交互时服务端可以通过 res.redirect 对客户端进行重定向,但异步交互时,服务端重新定向是无效的。因此只能客户端判断跳转。

<script>
    $("#register_form").on('submit', function (e) {
        e.preventDefault() //禁止表单的默认提交行为
        var formData = $(this).serialize()
        $.ajax({
            url: '/register',
            type: 'post',
            data: formData,
            dataType: 'json',
            success: function (data) {
                var err_code = data.err_code
                if (err_code === 0) {
                    window.location.href = '/' // 服务端重定向针对异步请求无效
                } else if (err_code === 1) {
                    window.alert('邮箱或昵称已存在!')
                } else if (err_code === 500) {
                    window.alert('服务器忙,请稍后重试!')
                }
            }
        })
    })
</script>

配置密码加密插件 md5

用户注册时需要存储用户的密码到数据库,为了防止密码泄露,保证用户密码的安全性,我们需要对用户密码进行加密,md5 是一种常用的加密方式。在 github 查找 node md5 找到 node 中使用的 md5 插件:blueimp-md5

github 找 md5 插件

Cookie 与 Session

参考博客:https://www.cnblogs.com/whgk/p/6422391.html

Cookie和Session之间的区别和联系

假如一个咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠,然而一次性消费5杯咖啡的机会微乎其微,这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案:

1、该店的店员很厉害,能记住每位顾客的消费数量,只要顾客一走进咖啡店,店员就知道该怎么对待了。这种做法就是协议本身支持状态。但是http协议本身是无状态的

2、发给顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会与以前或以后的消费相联系起来。 顾客就相当于浏览器。这种做法就是在客户端保持状态。也就是cookie。

3、发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。也就是session。

Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。session和cookie的作用是类似的,都是为了存储用户相关的信息。

Cookie的机制

在网站中,http请求是无状态的,也就是说,即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。cookie的出现就是为了解决这个问题:浏览器请求服务器访问web站点时,服务器通过 http 响应将Cookie数据回给浏览器,浏览器将cookie数据存放在客户端内存中,当该用户发送第二次请求的时候,就会自动的把上次请求存储的cookie数据自动携带给服务器,服务器通过浏览器携带的数据就能识别当前用户。

cookie中的Domain和Path属性标识了这个cookie是哪一个网站发送给浏览器的;Expires属性标识了cookie的有效时间:

  1. 如果对Expires属性进行有效时间设置,当cookie的有效时间过了之后,这些数据就被自动删除了;此时会话cookie保存在硬盘上。关闭浏览器后再次打开,这些cookie依然有效,直到超过设定的有效时间。存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗 口。

  2. 如果不设置过期时间,则表示这个cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失。这种生命期为浏览会话期的cookie被称为会话cookie。会话cookie一般不保存在硬盘上,而是保存在内存里。

特点:cookie存储在本地浏览器,且存储数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据。
Session的机制

Session的机制

浏览器请求服务器访问web站点时,程序需要为客户端的请求创建一个session的时候,服务器首先会检查这个客户端请求是否已经包含了一个session标识、称为SESSIONID,如果已经包含了一个sessionid则说明以前已经为此客户端创建过session,服务器就按照sessionid把这个session检索出来使用,如果客户端请求不包含session id,则服务器为此客户端创建一个session并且生成一个与此session相关联的session id,sessionid 的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个sessionid将在本次响应中返回到客户端保存,保存这个sessionid的方式就可以是cookie,这样在交互的过程中,浏览器可以自动的按照规则把这个标识发回给服务器,服务器根据这个sessionid就可以找得到对应的session。

一般情况下,服务器会在一定时间内(默认20分钟)保存这个session,过了时间限制,就会销毁这个session。在销毁之前,程序员可以将用户的一些数据以Key和Value的形式暂时存放在这个session中。默认 Session 数据是内存存储的,服务器一旦重启就会丢失,也有使用数据库将这个session序列化后保存起来的,这样的好处是没了时间的限制,坏处是随着时间的增加,这个数据库会急速膨胀,特别是访问量增加的时候。一般还是采取前一种方式,以减轻服务器压力。

特点:cookie存储在本地浏览器,而session存储在服务器。存储在服务器的数据会更加的安全,不容易被窃取。但会占用服务器的资源。

在 Express 中配置使用 express-session 插件

在 express 中,默认不支持 Session 和 Cookie,但是我们可以使用第三方中间件:express-session 来解决:

var session = require('express-session')
var app = express()

app.use(session({
  secret: 'keyboard cat', //配置加密字符串
  resave: false,
  saveUninitialized: true,
  // cookie: { secure: true } cookie 安全限制 https 协议
}))
  1. secret属性是配置加密字符串,它会在原有加密基础之上和这个字符串拼起来去加密,加密后的字符串作为 session id 发送给浏览器。目的是为了增加安全性,防止客户端恶意伪造
  2. saveUninitialized 属性为 true 则无论你是否使用 Session,都默认直接分配一个session id 给客户端。为 false 则真正存数据的时候才会分配 session id 给客户端
  3. 当secure属性设置为true时,cookie只有在https协议下才能上传到服务器,而在http协议下是没法上传的,所以也不会被窃听。
// 添加 Session 数据
req.session.foo = 'bar'

// 访问 Session 数据
req.session.foo
上一篇下一篇

猜你喜欢

热点阅读