nodejs -会话控制学习笔记

打印 上一主题 下一主题

主题 519|帖子 519|积分 1557

一、介绍

会话控制就是 对会话(根据用户)进行控制。
HTTP 是一种无状态的协议,它没有办法区分多次的哀求是否来自于同一个客户端(客户),无法区分用户,而产品中又大量存在这样的需求,所以必要会话控制办理该问题。
常见的会话控制技能有三种:


  • cookie
  • session
  • token
二、cookie

1、是什么

cookie 是 HTTP 服务器发送到用户欣赏器并保存在本地的一小块数据(不必要前端手动存储,后端设置cookie以后,相应头上会上,之后,前端发送任何哀求,都会自动将 cookie 携带在哀求头中)。
cookie 是保存在欣赏器的一小块数据,是按照域名分别的。

1-2、特点

欣赏器向服务器发送哀求时,会自动将 当前域名 下可用的 cookie 设置在哀求头中,然后通报给服务器。
1-3、cookie 的运行流程

填写账号和暗码校验身份,校验通事后下发 cookie

有了 cookie 之后,后续向服务器发送哀求时,会自动携带 cookie

1-4、欣赏器操纵 cookie

欣赏器操纵 cookie 相对较少,仅做了解

  • 禁用所有 cookie
  • 删除 cookie
  • 查察 cookie
控制台 -》 应用(Application) -》Cookies
控制台 -》 网络(NetWork) -》 哀求头
欣赏器 -》 设置
1-5、代码对 cookie 增删查

  1. const express = require('express')
  2. const app = express()
  3. // 获取 cookie 时需要用到 cookie-parser
  4. const cookieParser = require('cookie-parser')
  5. app.use(cookieParser())
  6. app.get('/', (req, res) => {
  7.   res.send('home')
  8. })
  9. // 设置 cookie
  10. app.get('/setCookie', (req, res) => {
  11.   // 设置 cookie,会在浏览器关闭(退出后台)的时候销毁
  12.   // 如果提前打开了两个 独立 的tab页,把 访问http://127.0.0.1:3000/的页面关掉以后
  13.   // 另一个页面还是会存在 cookie
  14.   res.cookie('name', 'zhangsan')
  15.   // 设置 cookie 键值对和过期时间,maxAge 单位是毫秒,30 * 1000 = 30s
  16.   // cookie 会在 30 秒之后销毁,常用于做 7天免登录
  17.   // res.cookie('name','zhangsan',{maxAge: 30 * 1000})
  18.   res.cookie('theme', 'blue')
  19.   res.send('cookie')
  20. })
  21. // 删除 cookie
  22. app.get('/removeCookie', (req, res) => {
  23.   // 删除 cookie,参数是必填项
  24.   res.clearCookie('theme')
  25.   res.send('成功删除cookie')
  26. })
  27. // 获取 cookie
  28. app.get('/getCookie', (req, res) => {
  29.   // 获取cookie
  30.   // res.send( req.cookies)
  31.   res.send( req.cookies.name)
  32.   // res.send( req.cookies.theme)
  33. })
  34. app.listen(3000, () => {
  35.   console.log('服务器已经启动....')
  36. })
复制代码
三、session

1、是什么

session 是保存在 服务端的一块数据,保存当前访问用户的信息。
2、作用

实现会话控制,可以识别用户的身份,快速获取当前用户的相干信息。
3、运行流程

填写账号、暗码校验身份,校验通事后创建 session 信息,然后将 session_id 的值通过相应头返回给欣赏器

有了 cookie ,下次发送哀求时会自动携带 cookie,服务器通过 cookie 中的 session_id 的值确定用户的身份

4、代码对 session 增删查

  1. const express = require('express')
  2. // 下载 npm i express-session connect-mongo
  3. // 引入 express-session、connect-mongo
  4. const session = require('express-session')
  5. const MongoStore = require('connect-mongo')
  6. const app = express()
  7. app.use(session({
  8.   name: 'sid',    // 设置 cookie 的 name,默认值是:connect.sid
  9.   secret: 'zhangsan',   // 参与加密的字符串(又称签名)
  10.   saveUninitialized: false,   // 是否为每次请求都设置一个cookie用来存储session的id
  11.   resave: true,   // 是否在每次请求时重新保存session,
  12.   // 场景:为 true 时,假如一个网站的session的过期时间时 20 分钟,每次请求之后,会重置这个时间
  13.   // 直到不做任何请求之后的 20 分钟,才会销毁session_id
  14.   store: MongoStore.create({
  15.     mongoUrl: 'mongodb://127.0.0.1:27017/bilibili'  // 数据库的连接配置
  16.   }),
  17.   cookie: {
  18.     httpOnly: true,   // 开启后前端无法通过 js 操作(document.cookie)获取到 cookie
  19.     maxAge: 1000 * 60 * 5 // sessionID 的过期时间 5 分钟
  20.   }
  21. }))
  22. // 设置 session
  23. app.get('/login', (req, res) => {
  24.   if(req.query.username === 'admin' && req.query.password === 'admin') {
  25.     // 设置 session 信息
  26.     req.session.username = 'admin'
  27.     req.session.uid = '258aefefdf'
  28.     res.send('登录成功')
  29.   } else {
  30.     res.send('登录失败')
  31.   }
  32. })
  33. // session 的读取
  34. app.get('/cart', (req, res) => {
  35.   // 判断用户是否登录--》检测session 是否存在用户数据
  36.   if(req.session.username) {
  37.     res.send(`购物车页面欢迎你 ${req.session.username}`)
  38.   } else {
  39.     res.send('你还没有登录')
  40.   }
  41. })
  42. // session 销毁
  43. app.get('/logout', (req, res) => {
  44.   req.session.destroy(() => {
  45.     res.send('退出成功')
  46.   })
  47. })
  48. app.get('/', (req, res) => {
  49.   res.send('首页')
  50. })
  51. app.listen(3000, () => {
  52.   console.log('服务启成功')
  53. })
复制代码
四、session 和 cookie 的区别

cookie 和 session 的区别主要有以下几点:

  • 存放的位置
    cookie:欣赏器端
    session: 服务端
  • 安全性
    cookie 是以明文的方式存放在客户端的,安全性相对较低
    session 存放在 服务端,所以安全性相对较好
  • 网络传输量
    cookie 设置内容过多会增大报文体积,影响传输效率
    session 数据存储在服务器,只能通过 cookie 通报 id,所以不影响传输效率
  • 存储表现
    欣赏器限定单个 cookie 保存的数据不能超过 4k,且单个域名下的存储数量也有限定
    session 数据存储在 服务器 中,所以没有这个限定
五、token

1、是什么

token 时服务端生成并返回给 HTTP 客户端的一串加密字符串,token 中保存着用户信息
2、作用

实现会话控制,可以识别用户的身份,主要用于移动端 app
3、token 的工作流程

填写账号和暗码校验身份,校验通事后相应 token,token 一样寻常是在相应体中返回给客户端

后续发送哀求时,必要手动将 token 添加在哀求报文中,一样寻常是放在哀求头中

4、特点


  • 服务端压力更小
    数据存储在客户端
  • 相对更安全
    数据加密
    可以避免 CSRF(跨站哀求伪造)
  • 扩展性更强
    服务可以共享
    增长服务节点更简朴
5、JWT

JWT (JSON Web Token)是目前最流行的跨域认证办理方案,可用于 基于 token 的身份验证
JWT 使 token 的生成与校验更规范
npm i jsonwebtoken
  1. const jwt = require('jsonwebtoken')
  2. // 创建 token
  3. // let token = jwt.sign({
  4. //   username: 'zhangsan'
  5. // }, 'nodejs-token', {
  6. //   expiresIn: 60 // 单位是 秒
  7. // })
  8. // token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InpoYW5nc2FuIiwiaWF0IjoxNzIxODkyMjMzLCJleHAiOjE3MjE4OTIyOTN9.EpSHpeYuf7KOjptpTftrSZyAJ1234xvcgnvc6_PBdYQ
  9. // console.log(token)
  10. let t = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InpoYW5nc2FuIiwiaWF0IjoxNzIxODkyMjMzLCJleHAiOjE3MjE4OTIyOTN9.EpSHpeYuf7KOjptpTftrSZyAJ1234xvcgnvc6_PBdYQ'
  11. // 校验 token
  12. jwt.verify(t, 'nodejs-token', (err, data) => {
  13.   if(err) {
  14.     console.log('校验失败')
  15.     return
  16.   }
  17.   console.log(data) // { username: 'zhangsan', iat: 1721892343, exp: 1721892403 }
  18. })
复制代码
流程:

  • 登录乐成后,服务端生成 token,并返回给前端
  1. const express = require('express')
  2. const router = express.Router()
  3. const md5 = require('md5')
  4. const UserModel = require('../../models/UserModel')
  5. const jwt = require('jsonwebtoken')
  6. // 登录功能的路由
  7. router.post('/login', (req, res) => {
  8.   let { username, password } = req.body
  9.   UserModel.findOne({username, password: md5(password)}).then((data) => {
  10.     if(!data) {
  11.       return res.json({
  12.         code: '2001',
  13.         msg: '账号或密码错误',
  14.         data: null
  15.       })
  16.     }
  17.     req.session.username = data.username
  18.     req.session._id = data._id
  19.     // res.render('success', {msg:'登录成功',url:'/account'})
  20.     // 创建当前用户的 token
  21.     // nodejs-token 为加密字符串
  22.     let token = jwt.sign({
  23.       username: data.username,
  24.       _id: data._id
  25.     }, 'nodejs-token', {
  26.       expiresIn: 60 * 60 * 24 * 7   // token 过期时间为 1 周
  27.     })
  28.     res.json({
  29.       code: '0000',
  30.       msg: '登录成功',
  31.       data: token
  32.     })
  33.   }).catch(() => {
  34.     // res.render('success', {msg:'登录失败',url:'/login'})
  35.     // res.status(500).send('登录失败,请稍后重试')
  36.     res.json({
  37.       code: '2002',
  38.       msg: '登录失败,请稍后重试',
  39.       data: null
  40.     })
  41.   })
  42. })
  43. module.exports = router
复制代码

  • 前端拿到 token 后,在每次哀求时,都要将 token 写到哀求头中
  • 前端哀求时,将token放入哀求头后,后端处置惩罚哀求:
    api/auth.js
  1. const express = require('express');
  2. const router = express.Router();
  3. const AccountModel = require('../../models/AccountModel')
  4. const dayjs = require('dayjs')
  5. // 配置中间件 =》校验 token
  6. const CheckTokenMiddleware = require('../../middlewares/CheckTokenMiddleware')
  7. router.post('/account', CheckTokenMiddleware,(req, res, next) => {
  8.   AccountModel.create({
  9.     ...req.body,
  10.     time: dayjs(req.body.time).format()
  11.   }).then((data) => {
  12.     console.log(data)
  13.     // res.render('success', {msg:'添加成功了',url:'/account'})
  14.     res.json({
  15.       code: '0000',
  16.       msg: '创建成功',
  17.       data: data
  18.     })
  19.   }).catch(() => {
  20.     // res.status(500).send('删除失败了')
  21.     res.json({
  22.       code: '1002',
  23.       msg: '创建失败',
  24.       data: null
  25.     })
  26.   })
  27. });
  28. router.get('/account/remove/:id', CheckTokenMiddleware, (req, res) => {
  29.   //获取 params 的 id 参数
  30.   let id = req.params.id
  31.   AccountModel.deleteOne({_id: id}).then((data) => {
  32.     // console.log(data)
  33.     // res.render('success', {msg:'删除成功了',url:'/account'})
  34.     res.json({
  35.       code: '0000',
  36.       msg: '删除成功',
  37.       data: {}
  38.     })
  39.   }).catch(() => {
  40.     // res.status(500).send('删除失败了')
  41.     res.json({
  42.       code: '1003',
  43.       msg: '删除失败',
  44.       data: null
  45.     })
  46.   })
  47. })
  48. module.exports = router;
复制代码
models/AccountModel.js
  1. const mongoose = require('mongoose')
  2. const AccountSchema = new mongoose.Schema({
  3.   title: {
  4.     type: String,
  5.     required: true
  6.   },
  7.   time: Date,
  8.   type: {
  9.     type: Number,
  10.     default: -1
  11.   },
  12.   account: {
  13.     type: Number,
  14.     required: true
  15.   },
  16.   remarks: String
  17. })
  18. const AccountModel = mongoose.model('account', AccountSchema)
  19. module.exports = AccountModel
复制代码
middlewares/CheckTokenMiddleware.js
  1. const jwt = require('jsonwebtoken')
  2. module.exports = (req, res, next) => {
  3.   const token = req.get('token')
  4.   jwt.verify(token, 'nodejs-token', (err, data) => {
  5.     if(err) {
  6.       return res.json({
  7.         code: '2003',
  8.         msg: 'token 校验失败',
  9.         data: null
  10.       })
  11.     }
  12.    
  13.     next()
  14.   })
  15. }
复制代码
六、扩展

1、本地域名

所谓本地域名就是 只能在本机使用的域名 ,一样寻常在开发阶段使用
1-1、操纵流程

编辑文件 C:\Windows\System32\drivers\etc\hosts
  1. 127.0.0.1 www.baidu.com
复制代码
假如修改失败, 可以修改该文件的权限

1-2、原理

在地点栏输入 域名 后,欣赏器会先辈行 DNS (Domain Name System)查询,湖区该域名对应的 IP 地点
哀求会发送到 DNS 服务器,可以 根据域名返回 IP 地点
可以通过 ipconfig /all查察本机的 DNS 服务器
hosts 文件也可以设置域名与 IP 的映射关系,在发送哀求前,可以通过该文件获取域名的 IP 地点

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

我爱普洱茶

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表