状态管理
概念:
将浏览器与web服务器的多次交互当作一个整体来处理,将多次交互所涉及的数据状态保存下来。
管理方式1:将状态保存在浏览器,需要使用cookie技术
管理方式2:将状态保存在服务器,需要使用session技术
一:cookie
cookie是一种客户端的状态管理技术。
当浏览器访问服务器时,服务器会将一些信息以set_cookie消息头的形式发送给浏览器,浏览器会将这些数据保存下来,当浏览器再次访问服务器时,会将这些数据以cookie消息头的形式一并发送给服务器。(有几个cookie,就有几个消息头)。
二:session
服务端为了维护保存状态而创建的特殊对象。
1.原理
1.浏览器第一次请求服务器,服务器创建session对象
2.session对象产生一个唯一的sessionid
3.服务器将sessionid返回给浏览器并存放在cookie中
4.浏览器第二次请求服务器,将sessionid提交给服务器
5.服务器拿到sessionid去查找匹配的session对象
2.会话结束的情况
1.服务器把sessionid删掉了
2.浏览器把cookie里面的sessionid给清除了
3.特点
- 放在服务器端
- 不存在大小的限制
- 每一个用户都有自己独立的session对象
- 每个session都有一个sid
- sid存在cookie里面或者其他地方(比如localStorage)
4.缺点
- 消耗服务器内存
- 存在集群环境下的共享问题
5.操作
- 下载express-session插件
npm i express-session
- 在app.js中引入session
//引入session插件
var session = require('express-session');
- 在app.js中的静态页面后写写关于session的配置
//必须在静态页面后面写
app.use(session({
secret:"lovo", // 加密密钥
resave:false, // 强制保存session,默认为true,即使它没有变化,建议false
saveUninitialized:true // 强制将未初始化的session存储(当新建一个sesison,但未设定属性和值时处于未初始化状态)
}));
- 在你要存入session对象的地方,把数据添加到session里面(如:在我的登录的地方存放我的用户信息数据)
//登录成功后把信息存放在session里面
router.post('/login',async function (req, res) {
let { username, userpwd } = req.body;
let data = await userService.login({username,userpwd});
console.log(data);
if (data.length > 0) {
//成功后将数据添加到session对象里面
req.session.user = data[0];
res.send({
status:1
});
}
else {
res.send({
status:0
});
}
});
- 在表现层写入方法来获取服务器中现存得session对象(如:我需要在登成功的时候才能跳到信息管理页面且用户那显示的名字是我的名字,还有在没有登录的情况下信息管理页面无法打开)index.js
//创建一个获取session对象的方法,提供给浏览器获取session的方法
router.get("/getSession",function(req,res){
let user = req.session.user;
//在有数据的时候就返回数据,没数据的时候就返回一个空对象
res.send({data:user || {}});
})
//点击注销的时候删除session方法
router.get("/removeSession",function(req,res){
//比如在我点击一个东西需要退出的时候,就把我的用户信息给清空
req.session.user = null;
res.send({status:1});
})
- 然后在页面需要显示的地方用ajax来获取信息来显示
//用ajax方法来获取传来的session对象名字
$.ajax({
type:"get",
url:"/getSession",
success(res){
console.log(res.data.username);
//还有当用户信息不存在的时候刷新会返回登录页面
//Object.keys(res.data).length==>当前对象长度,如果长度等于0,说明session里面没有用户信息,你要直接访问信息管理就不能访问
if(Object.keys(res.data).length == 0){
location.href = "#login";
}else{
$("#username").html(res.data.username);
}
}
})
//点击退出的时候就跳转到登录页面,
$("#removeSession").click(function(){
$.ajax({
type:"get",
url:"/removeSession",
success(res){
console.log(res,res.status);
if(res.status == "1"){
location.href = "#login";
}
}
})
})
三:token
token验证失败返回401;
0.原理
1.浏览器第一次请求服务器,服务器会将状态信息进行签名(加密)并生成token
2.服务器将token返回响应给浏览器
3.浏览器接收到token后保存在浏览器中(cookie,local,session)
4.浏览器再次请求服务器并将token提交给服务器
5.服务器接收到token后进行解密并获取到其中的状态信息
1.优缺点
优点
- 更高的安全性 (cookie缺点token优点)
- 没有大小的限制 (cookie缺点~)
- 不会消耗服务器的内存 (session缺点~)
- 更适合集群下状态的管理 (session缺点~)
缺点
- 开发难度高点
2.加密算法
2.1对称加密
只有一把钥匙,加密和解密是同一把钥匙;举个例子:开门,关门只需要一把钥匙就行,这把钥匙叫:密钥
代表性:AES,DES
2.2非对称加密
有两把钥匙,加密:公钥;解密:私钥;举个例子:比如锁和钥匙,加密就是锁,解密就是钥匙
代表性:RSA
2.3hash加密
别名:散列算法,哈希算法
单向加密,不能还原,只能加密不能解密,除非破解密码
一般用来测试安全性
代表性:MD5,sha-1,sha-256,sha-512
- 下载插件
npm i crypto
- 用的sha-256,封装方法,新建一个util.js来配置
const crypto = require('crypto');
module.exports.sha256 = function(str){
let sha = crypto.createHash('sha256');
return sha.update(str).digest('hex');
}
- 给密码加密
//引入util文件
const {sha256} = require("../util");
//给密码加密
//注册
router.post('/reg',async function (req, res) {
let { username, userpwd } = req.body;
//给密码加密:userpwd:sha256(userpwd)
let data = await userService.insert({username,userpwd:sha256(userpwd)});
console.log(data);
res.send({
msg:"注册成功",
data
});
});
3.操作
- 下载中间件
作用:获取浏览器返回的tooken信息来进行解密
//可删除jwt
npm uninstall express-jwt
//下载的是最新版的
npm i express-jwt
//可控制下载版本
npm i express-jwt@6
- 引入中间件(app.js)
//引入可以获取浏览器返回的tooken信息来进行解密
var jwt = require('express-jwt');
- 配置token (app.js)
const {secretKey,algorithms,unless} = require('./util');
- 在工具文件里面配置中间件(util.js)
//algorithms:设置算法,可以通过对称加密啥的算法
//secretKey:设置密钥
//unless:设置需要排除的路径,里面的路径可以以正则的方式写
module.exports= {
//配置token中间件
"secretKey":"lovo",
"algorithms":["HS256"],
"unless":{
path:[
/^\/users\/.*/,"/favicon.ico","/upload"
]
},
//配置加密算法
sha256(str){
let sha = crypto.createHash('sha256');
return sha.update(str).digest('hex');
}
}
- 在登陆成功后生成token
- 生成token的插件
npm i jsonwebtoken
- 加密签字生成token(表现层user.js中登录成功后)
//数据,密钥
//加密签字生成token
let token = jwt.sign({data:data[0]}, secretKey);
//登陆成功响应回浏览器
res.send({
token,
status:1
});
- 测试
//中间件规范(记得在请求头里面测试)
//authorzation格式,Bearer token字符串
authorzation:请求头
Bearer token加密后的字符串
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gqS8laik-1651244787189)(E:\node.js\img\token.png)]
- 解密(表现层index.js)
//token
router.get("/getToken",function(req,res){
//获取到客户端发送过来的token
const token = req.get("Authorization");
console.log("token",token);
//将编码后的token再转换过来
const data = jwt.verify(token.split(" ")[1],secretKey);
res.send({data:data.data});
})
- 把登录成功后的数据上传到浏览器的localStorage里面(pages里面的login.js)
localStorage.token = res.token;
- 然后给ajax配置一个全局变量的请求头
// 设置ajax的全局属性,用于提交token信息
$.ajaxSettings.beforeSend = function(xhr){
// 在这里加上你的 token
//setRequestHeader:设置请求头
xhr.setRequestHeader('Authorization','Bearer ' + localStorage.token);
}
$.ajaxSettings.error = function(err){
if(err.status == 401){
location.href = "#login";
}
}
- 在manage.js获取登录信息
$.ajax({
type:"get",
url:"/getToken",
success(res){
$("#username").html(res.data.username);
}
})
四:比较cookie 与 session 的优缺点:
cookie 优点: 不占用服务器的内存资源。
session 的优点: 安全,且可以保存更丰富的数据类型。
session 的缺点:可能会占用过多的内存空间,多台服务器负载均衡,session 同步+
$.ajax({
type:"get",
url:"/getToken",
success(res){
$("#username").html(res.data.username);
}
})
四:比较cookie 与 session 的优缺点:
cookie 优点: 不占用服务器的内存资源。
session 的优点: 安全,且可以保存更丰富的数据类型。
session 的缺点:可能会占用过多的内存空间,多台服务器负载均衡,session 同步+