一、介绍
会话控制就是 对会话(根据用户)进行控制。
HTTP 是一种无状态的协议,它没有办法区分多次的哀求是否来自于同一个客户端(客户),无法区分用户,而产品中又大量存在这样的需求,所以必要会话控制办理该问题。
常见的会话控制技能有三种:
二、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 增删查
- 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 的值通过相应头返回给欣赏器
有了 cookie ,下次发送哀求时会自动携带 cookie,服务器通过 cookie 中的 session_id 的值确定用户的身份
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 一样寻常是在相应体中返回给客户端
后续发送哀求时,必要手动将 token 添加在哀求报文中,一样寻常是放在哀求头中
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 }
- })
复制代码 流程:
- 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
假如修改失败, 可以修改该文件的权限
1-2、原理
在地点栏输入 域名 后,欣赏器会先辈行 DNS (Domain Name System)查询,湖区该域名对应的 IP 地点
哀求会发送到 DNS 服务器,可以 根据域名返回 IP 地点
可以通过 ipconfig /all查察本机的 DNS 服务器
hosts 文件也可以设置域名与 IP 的映射关系,在发送哀求前,可以通过该文件获取域名的 IP 地点
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |