我爱普洱茶 发表于 2024-8-1 07:09:14

nodejs -会话控制学习笔记

一、介绍

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


[*]cookie
[*]session
[*]token
二、cookie

1、是什么

cookie 是 HTTP 服务器发送到用户欣赏器并保存在本地的一小块数据(不必要前端手动存储,后端设置cookie以后,相应头上会上,之后,前端发送任何哀求,都会自动将 cookie 携带在哀求头中)。
cookie 是保存在欣赏器的一小块数据,是按照域名分别的。
https://i-blog.csdnimg.cn/direct/85a1608a6a1d466185bb76ece8e934c0.png
1-2、特点

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

填写账号和暗码校验身份,校验通事后下发 cookie
https://i-blog.csdnimg.cn/direct/80149769a8eb468e81a1f848db40a0c8.png
有了 cookie 之后,后续向服务器发送哀求时,会自动携带 cookie
https://i-blog.csdnimg.cn/direct/48b22e6c4f3048388731879f861d000d.png
1-4、欣赏器操纵 cookie

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

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

const express = require('express')
const app = express()
// 获取 cookie 时需要用到 cookie-parser
const cookieParser = require('cookie-parser')
app.use(cookieParser())

app.get('/', (req, res) => {
res.send('home')
})

// 设置 cookie
app.get('/setCookie', (req, res) => {
// 设置 cookie,会在浏览器关闭(退出后台)的时候销毁
// 如果提前打开了两个 独立 的tab页,把 访问http://127.0.0.1:3000/的页面关掉以后
// 另一个页面还是会存在 cookie
res.cookie('name', 'zhangsan')

// 设置 cookie 键值对和过期时间,maxAge 单位是毫秒,30 * 1000 = 30s
// cookie 会在 30 秒之后销毁,常用于做 7天免登录
// res.cookie('name','zhangsan',{maxAge: 30 * 1000})

res.cookie('theme', 'blue')
res.send('cookie')
})

// 删除 cookie
app.get('/removeCookie', (req, res) => {
// 删除 cookie,参数是必填项
res.clearCookie('theme')
res.send('成功删除cookie')
})

// 获取 cookie
app.get('/getCookie', (req, res) => {
// 获取cookie
// res.send( req.cookies)
res.send( req.cookies.name)
// res.send( req.cookies.theme)
})

app.listen(3000, () => {
console.log('服务器已经启动....')
})
三、session

1、是什么

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

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

填写账号、暗码校验身份,校验通事后创建 session 信息,然后将 session_id 的值通过相应头返回给欣赏器
https://i-blog.csdnimg.cn/direct/b1af9f41f49d4710a134b7ea810d5b0a.png
有了 cookie ,下次发送哀求时会自动携带 cookie,服务器通过 cookie 中的 session_id 的值确定用户的身份
https://i-blog.csdnimg.cn/direct/da2554d51158471288c2ef59a32a54eb.png
4、代码对 session 增删查

const express = require('express')

// 下载 npm i express-session connect-mongo
// 引入 express-session、connect-mongo
const session = require('express-session')
const MongoStore = require('connect-mongo')


const app = express()
app.use(session({
name: 'sid',    // 设置 cookie 的 name,默认值是:connect.sid
secret: 'zhangsan',   // 参与加密的字符串(又称签名)
saveUninitialized: false,   // 是否为每次请求都设置一个cookie用来存储session的id
resave: true,   // 是否在每次请求时重新保存session,
// 场景:为 true 时,假如一个网站的session的过期时间时 20 分钟,每次请求之后,会重置这个时间
// 直到不做任何请求之后的 20 分钟,才会销毁session_id
store: MongoStore.create({
    mongoUrl: 'mongodb://127.0.0.1:27017/bilibili'// 数据库的连接配置
}),
cookie: {
    httpOnly: true,   // 开启后前端无法通过 js 操作(document.cookie)获取到 cookie
    maxAge: 1000 * 60 * 5 // sessionID 的过期时间 5 分钟
}
}))

// 设置 session
app.get('/login', (req, res) => {
if(req.query.username === 'admin' && req.query.password === 'admin') {
    // 设置 session 信息
    req.session.username = 'admin'
    req.session.uid = '258aefefdf'
    res.send('登录成功')
} else {
    res.send('登录失败')
}
})

// session 的读取
app.get('/cart', (req, res) => {
// 判断用户是否登录--》检测session 是否存在用户数据
if(req.session.username) {
    res.send(`购物车页面欢迎你 ${req.session.username}`)
} else {
    res.send('你还没有登录')
}
})

// session 销毁
app.get('/logout', (req, res) => {
req.session.destroy(() => {
    res.send('退出成功')
})
})

app.get('/', (req, res) => {
res.send('首页')
})

app.listen(3000, () => {
console.log('服务启成功')
})
四、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 一样寻常是在相应体中返回给客户端
https://i-blog.csdnimg.cn/direct/2fb2c8595350464cb4860498c4cc1018.png
后续发送哀求时,必要手动将 token 添加在哀求报文中,一样寻常是放在哀求头中
https://i-blog.csdnimg.cn/direct/18d83417d171434591e452c64ee1cfdc.png
4、特点


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

JWT (JSON Web Token)是目前最流行的跨域认证办理方案,可用于 基于 token 的身份验证
JWT 使 token 的生成与校验更规范
npm i jsonwebtoken
const jwt = require('jsonwebtoken')

// 创建 token
// let token = jwt.sign({
//   username: 'zhangsan'
// }, 'nodejs-token', {
//   expiresIn: 60 // 单位是 秒
// })

// token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InpoYW5nc2FuIiwiaWF0IjoxNzIxODkyMjMzLCJleHAiOjE3MjE4OTIyOTN9.EpSHpeYuf7KOjptpTftrSZyAJ1234xvcgnvc6_PBdYQ
// console.log(token)

let t = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InpoYW5nc2FuIiwiaWF0IjoxNzIxODkyMjMzLCJleHAiOjE3MjE4OTIyOTN9.EpSHpeYuf7KOjptpTftrSZyAJ1234xvcgnvc6_PBdYQ'
// 校验 token
jwt.verify(t, 'nodejs-token', (err, data) => {
if(err) {
    console.log('校验失败')
    return
}
console.log(data) // { username: 'zhangsan', iat: 1721892343, exp: 1721892403 }
})
流程:

[*]登录乐成后,服务端生成 token,并返回给前端
const express = require('express')
const router = express.Router()
const md5 = require('md5')
const UserModel = require('../../models/UserModel')
const jwt = require('jsonwebtoken')


// 登录功能的路由
router.post('/login', (req, res) => {
let { username, password } = req.body
UserModel.findOne({username, password: md5(password)}).then((data) => {
    if(!data) {
      return res.json({
      code: '2001',
      msg: '账号或密码错误',
      data: null
      })
    }

    req.session.username = data.username
    req.session._id = data._id

    // res.render('success', {msg:'登录成功',url:'/account'})

    // 创建当前用户的 token
    // nodejs-token 为加密字符串
    let token = jwt.sign({
      username: data.username,
      _id: data._id
    }, 'nodejs-token', {
      expiresIn: 60 * 60 * 24 * 7   // token 过期时间为 1 周
    })
    res.json({
      code: '0000',
      msg: '登录成功',
      data: token
    })
}).catch(() => {
    // res.render('success', {msg:'登录失败',url:'/login'})
    // res.status(500).send('登录失败,请稍后重试')
    res.json({
      code: '2002',
      msg: '登录失败,请稍后重试',
      data: null
    })
})
})

module.exports = router

[*]前端拿到 token 后,在每次哀求时,都要将 token 写到哀求头中
[*]前端哀求时,将token放入哀求头后,后端处置惩罚哀求:
api/auth.js
const express = require('express');
const router = express.Router();

const AccountModel = require('../../models/AccountModel')
const dayjs = require('dayjs')

// 配置中间件 =》校验 token
const CheckTokenMiddleware = require('../../middlewares/CheckTokenMiddleware')

router.post('/account', CheckTokenMiddleware,(req, res, next) => {
AccountModel.create({
    ...req.body,
    time: dayjs(req.body.time).format()
}).then((data) => {
    console.log(data)
    // res.render('success', {msg:'添加成功了',url:'/account'})

    res.json({
      code: '0000',
      msg: '创建成功',
      data: data
    })
}).catch(() => {
    // res.status(500).send('删除失败了')

    res.json({
      code: '1002',
      msg: '创建失败',
      data: null
    })
})
});

router.get('/account/remove/:id', CheckTokenMiddleware, (req, res) => {
//获取 params 的 id 参数
let id = req.params.id
AccountModel.deleteOne({_id: id}).then((data) => {
    // console.log(data)
    // res.render('success', {msg:'删除成功了',url:'/account'})

    res.json({
      code: '0000',
      msg: '删除成功',
      data: {}
    })
}).catch(() => {
    // res.status(500).send('删除失败了')

    res.json({
      code: '1003',
      msg: '删除失败',
      data: null
    })
})
})
module.exports = router;
models/AccountModel.js
const mongoose = require('mongoose')

const AccountSchema = new mongoose.Schema({
title: {
    type: String,
    required: true
},
time: Date,
type: {
    type: Number,
    default: -1
},
account: {
    type: Number,
    required: true
},
remarks: String
})
const AccountModel = mongoose.model('account', AccountSchema)
module.exports = AccountModel
middlewares/CheckTokenMiddleware.js
const jwt = require('jsonwebtoken')

module.exports = (req, res, next) => {
const token = req.get('token')
jwt.verify(token, 'nodejs-token', (err, data) => {
    if(err) {
      return res.json({
      code: '2003',
      msg: 'token 校验失败',
      data: null
      })
    }
   
    next()
})
}
六、扩展

1、本地域名

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

编辑文件 C:\Windows\System32\drivers\etc\hosts
127.0.0.1 www.baidu.com
假如修改失败, 可以修改该文件的权限
https://i-blog.csdnimg.cn/direct/bc6204c07ed342ada5a66761471ccff2.png
1-2、原理

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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: nodejs -会话控制学习笔记