【node进阶】深入浅出前后端身份验证(上)---session

✅ 作者简介:一名普通本科大三的学生,致力于提高前端开发能力
✨ 个人主页:前端小白在前进的主页
系列专栏 : node.js学习专栏
⭐️ 个人社区 : 个人交流社区
学习格言: ☀️ 打不倒你的会使你更强!☀️


【node进阶】深入浅出前后端身份验证(上)---session_第1张图片
前言

在node系列的 ==>web开发模式 | express应用程序生成器 这篇文章中讲解了web开发模式,让大家认识到了前端的SSR和CSR,学习完开发模式后,我们这篇就衔接着开发模式来学习在交互过程中最重要的一部分身份验证,话不多说,正文开始!

目录

  • 身份认证
    • 什么是身份认证
    • 为什么要用身份认证
    • 不同开发模式下的身份认证
  • Session认证机制
    • HTTP 协议的无状态性
    • 如何突破 HTTP 无状态的限制
    • 什么是 Cookie
    • Cookie 在身份认证中的作用
    • Cookie 不具有安全性
    • 提高身份认证的安全性
    • Session 的工作原理
  • Express中使用Session认证
    • 安装 express-session 中间件
    • 配置 express-session 中间件
    • 向 session 中存数据
    • 从 session 中取数据
    • 清空 session
    • Session小demo
  • 小结

身份认证

什么是身份认证

身份认证(Authentication)又称“身份验证”、“鉴权”,是指通过一定的手段,完成对用户身份的确认

  • 日常生活中的身份认证随处可见,例如:高铁的验票乘车,手机的密码或指纹解锁,支付宝或微信的支付密码等。
  • 在 Web 开发中,也涉及到用户身份的认证,例如:各大网站的手机验证码登录、邮箱密码登录、二维码登录等。

为什么要用身份认证

身份认证的目的,是为了确认当前所声称为某种身份的用户,确实是所声称的用户。例如,你去找快递员取快递,你要怎么证明这份快递是你的

在互联网项目开发中,如何对用户的身份进行认证,是一个值得深入探讨的问题。例如,如何才能保证网站不会错误的将“马云的存款数额”显示到“马化腾的账户”上。(不得不说,黑马哥举的例子真不错)


不同开发模式下的身份认证

对于服务端渲染前后端分离这两种开发模式来说,分别有着不同的身份认证方案

  • 服务端渲染(SSR)推荐使用 Session 认证机制
  • 前后端分离(CSR)推荐使用 JWT 认证机制

Session认证机制

HTTP 协议的无状态性

了解 HTTP 协议的无状态性是进一步学习 Session 认证机制的必要前提。
HTTP 协议的无状态性,指的是客户端的每次 HTTP 请求都是独立的,连续多个请求之间没有直接的关系,服务器不会主动保留每次 HTTP 请求的状态
【node进阶】深入浅出前后端身份验证(上)---session_第2张图片
在这里,黑马哥给大家举了一个例子,超市的收银员去收钱的时候,不可能记得住每个用户是不是vip会员(这就是http的无状态性),转到编程中去,就可以理解为浏览器不会保留你http请求的状态!


如何突破 HTTP 无状态的限制

对于超市来说,为了方便收银员在进行结算时给 VIP 用户打折,超市可以为每个 VIP 用户发放会员卡。
【node进阶】深入浅出前后端身份验证(上)---session_第3张图片
注意:现实生活中的会员卡身份认证方式,在 Web 开发中的专业术语叫做 Cookie


什么是 Cookie

Cookie 是存储在用户浏览器中的一段不超过 4 KB字符串。它由一个名称(Name)、一个值(Value)和其它几个用于控制 Cookie 有效期、安全性、使用范围的可选属性组成。
不同域名下的 Cookie 各自独立,每当客户端发起请求时,会自动当前域名下所有未过期的 Cookie 一同发送到服务器。

Cookie的几大特性

  • 自动发送
  • 域名独立
  • 过期时限
  • 4KB 限制

查看Cookie:
我们在这里以百度首页为例子,(首先按F12键)查看它的cookie:

【node进阶】深入浅出前后端身份验证(上)---session_第4张图片


Cookie 在身份认证中的作用

客户端第一次请求服务器的时候,服务器通过响应头的形式,向客户端发送一个身份认证的 Cookie,客户端会自动将 Cookie 保存在浏览器中
随后,当客户端浏览器每次请求服务器的时候,浏览器会自动将身份认证相关的 Cookie,通过请求头的形式发送给服务器,服务器即可验明客户端的身份。
【node进阶】深入浅出前后端身份验证(上)---session_第5张图片


Cookie 不具有安全性

由于 Cookie 是存储在浏览器中的,而且浏览器也提供了读写 Cookie 的 API,因此 Cookie 很容易被伪造,不具有安全性。因此不建议服务器将重要的隐私数据,通过 Cookie 的形式发送给浏览器。
【node进阶】深入浅出前后端身份验证(上)---session_第6张图片
在这里,黑马又举了例子,真心不错,万一其他用户伪造了会员卡,该咋办呢?这就体现出来了Cookie的不安全性
注意:千万不要使用 Cookie 存储重要且隐私的数据!比如用户的身份信息、密码等。


提高身份认证的安全性

为了防止客户伪造会员卡,收银员在拿到客户出示的会员卡之后,可以在收银机上进行刷卡认证。只有收银机确认存在的会员卡,才能被正常使用。
【node进阶】深入浅出前后端身份验证(上)---session_第7张图片
这种“会员卡 + 刷卡认证”的设计理念,就是 Session 认证机制的精髓


Session 的工作原理

【node进阶】深入浅出前后端身份验证(上)---session_第8张图片


Express中使用Session认证

安装 express-session 中间件

Express 项目中,只需要安装 express-session 中间件,即可在项目中使用 Session 认证

npm i express-session

配置 express-session 中间件

express-session 中间件安装成功后,需要通过 app.use()注册 session 中间件,示例代码如下:

const session = require('express-session')
app.use(
  session({
    secret: 'Bruce', // secret 的值为任意字符串
    resave: false,
    saveUninitalized: true,
  })
)

如果你对其中的属性感到困惑的话可以来官方文档查看(全英)==>express-session中间件详解


向 session 中存数据

中间件配置成功后,可通过 req.session 访问 session 对象,存储用户信息

app.post('/api/login', (req, res) => {
  req.session.user = req.body
  req.session.isLogin = true

  res.send({ status: 0, msg: 'login done' })
})

从 session 中取数据

app.get('/api/username', (req, res) => {
  if (!req.session.isLogin) {
    return res.send({ status: 1, msg: 'fail' })
  }
  res.send({ status: 0, msg: 'success', username: req.session.user.username })
})

清空 session

app.post('/api/logout', (req, res) => {
  // 清空当前客户端的session信息
  req.session.destroy()
  res.send({ status: 0, msg: 'logout done' })
})

Session小demo

项目结构:
【node进阶】深入浅出前后端身份验证(上)---session_第9张图片


index页面:

DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Documenttitle>
  <script src="./jquery.js">script>
head>

<body>
  <h1>首页h1>

  <button id="btnLogout">退出登录button>

  <script>
    $(function () {

      // 页面加载完成后,自动发起请求,获取用户姓名
      $.get('/api/username', function (res) {
        // status 为 0 表示获取用户名称成功;否则表示获取用户名称失败!
        if (res.status !== 0) {
          alert('您尚未登录,请登录后再执行此操作!')
          location.href = './login.html'
        } else {
          alert('欢迎您:' + res.username)
        }
      })

      // 点击按钮退出登录
      $('#btnLogout').on('click', function () {
        // 发起 POST 请求,退出登录
        $.post('/api/logout', function (res) {
          if (res.status === 0) {
            // 如果 status 为 0,则表示退出成功,重新跳转到登录页面
            location.href = './login.html'
          }
        })
      })
    })
  script>
body>

html>

登录页面:

DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Documenttitle>
  <script src="./jquery.js">script>
head>

<body>
  
  <form id="form1">
    <div>账号:<input type="text" name="username" />div>
    <div>密码:<input type="password" name="password" />div>
    <button>登录button>
  form>

  <script>
    $(function () {
      // 监听表单的提交事件
      $('#form1').on('submit', function (e) {
        // 阻止默认提交行为
        e.preventDefault()
        // 发起 POST 登录请求
        $.post('/api/login', $(this).serialize(), function (res) {
          // status 为 0 表示登录成功;否则表示登录失败!
          if (res.status === 0) {
            location.href = './index.html'
          } else {
            alert('登录失败!')
          }
        })
      })
    })
  script>
body>

html>

app.js文件

// 导入 express 模块
const express = require('express')
// 创建 express 的服务器实例
const app = express()

// TODO_01:请配置 Session 中间件
const session = require('express-session')
app.use(session({ 
  secret : 'wakaka',  //secret 属性的值可以是任何字符串
  resave:false, //固定写法,但是在官方文档中,建议使用true,但是通过http不会产生cookie,所以黑马哥用了false
  saveUninitialized:true
}))
// 托管静态页面
app.use(express.static('./pages'))
// 解析 POST 提交过来的表单数据
app.use(express.urlencoded({ extended: false }))

// 登录的 API 接口
app.post('/api/login', (req, res) => {
  // 判断用户提交的登录信息是否正确
  if (req.body.username !== 'admin' || req.body.password !== '000000') {
    return res.send({ status: 1, msg: '登录失败' })
  }

  // TODO_02:请将登录成功后的用户信息,保存到 Session 中
  req.session.user = req.body
  req.session.islogin = true
  res.send({ status: 0, msg: '登录成功' })
})

// 获取用户姓名的接口
app.get('/api/username', (req, res) => {
  // TODO_03:请从 Session 中获取用户的名称,响应给客户端
  if(!req.session.islogin) {
    return res.send({status :1,msg:'fail'})
  }
  res.send({ status:0,msg:'success',username:req.session.user.username })
})

// 退出登录的接口
app.post('/api/logout', (req, res) => {
  // TODO_04:清空 Session 信息
  req.session.destroy()
  res.send({
    status : 0,
    msg : '退出登录成功'
  })
})

// 调用 app.listen 方法,指定端口号并启动web服务器
app.listen(80, function () {
  console.log('Express server running at http://127.0.0.1:80')
})

小结

Session更加偏向于在服务端渲染中使用,可能在前后端交互主流的时代中,使用很少,但是是不可或缺的,大家主要去理解session的工作机制,在实战开发中是很重要的,在面试中也是必问的,下一篇的JWT是主流前后端分离中用的身份验证机制,希望大家持续关注更新哦!


【node进阶】深入浅出前后端身份验证(上)---session_第10张图片

你可能感兴趣的:(node.js入门到精通,前端,javascript,node.js,express)