会话控制
http请求是无状态的,无法区分多次的请求是否来自同一个客户端。
cookie
概念
1.最大存储4k
2.携带在每个http请求中,增加了流量
3.cookie是明文传输
4.对于浏览器外的其他客户端,如安卓、ios需要手动设置cookie和session
5.对于分布式系统和服务器集群中如何保证其他系统也可以正确解析session
express中使用cookie
cookie相关api
// 1.设置内存cookie 关闭浏览器时清除
res.cookie("name")
// 设置硬盘cookie 关闭浏览器不清除,到过期时间清除
res.cookie("name", "ccc", { maxAge: 60 * 1000 });
// 2.获取cookie
req.cookies
// 3.删除cookie
res.clearCookie("name");
koa中使用cookie
cookie相关api
// 1.设置内存cookie 关闭浏览器时清除
ctx.cookies.set(name, value, [options])
ctx.cookies.set('username', 'ccc', {
httpOnly: true,
maxAge: 86400000, // 一天
});
// 2.获取cookie
ctx.cookies.get(name, [options])
// 3.删除cookie
ctx.cookies.set('username', null, {
maxAge: 0, // 或者使用 expires 选项将过期时间设置为过去的时间戳
httpOnly: true,
});
session
概念
session和cookie类似,也是存储用户信息。不同是的是session存储在服务器,cookie存储在浏览器。
express中使用session
session相关api
req.session.username='张三'; //设置session
req.session.username //获取session
req.signedCookies.username //获取加密的cookie
req.session.cookie.maxAge=0; //重新设置cookie的过期时间,它会销毁所有的session
req.session.destroy(function(err) { /*销毁 session*/ })
req.session.username = "" //销毁指定的session
const express = require("express");
const router = express.Router();
const session = require("express-session");
const MongoStore = require("connect-mongo");
const md5 = require("md5");
// 使用express-session中间件
router.use(
session({
name: "sid", // session对应的cookie名称 默认为connect.sid
secret: "cjc", // 加盐
saveUninitialized: false, // 强制保存未初始化的session
resave: true, // 强制重新保存session,即使没有变化
store: MongoStore.create({
mongoUrl: "mongodb://127.0.0.1:27017/testDatabase",
}), // 数据库连接配置,在testDatabase下自动创建session集合
cookie: {
httpOnly: true, // 前端无法操作该cookie
maxAge: 1000 * 60, // cookie过期时间(故也是sessionID过期时间)
},
})
);
router.post("/register", express.json(), (req, res) => {
const { name, pwd } = req.body;
if (req.session.name === name) {
res.end(`${name}已注册`);
}
// 设置session,中间件自动将数据保存到数据库
req.session.name = name;
req.session.pwd = md5(pwd);
res.end(`${name}注册成功`);
});
router.post("/login", express.json(), (req, res) => {
const { name, pwd } = req.body;
if (md5(pwd) === req.session.pwd && name === req.session.name) {
req.session.name = name;
req.session.pwd = pwd;
res.end(`${name}登录成功`);
} else {
res.end("账号或密码错误");
}
});
router.post("/logout", express.json(), (req, res) => {
req.session.destroy((err) => {
if (err) {
res.end("cannot access session here");
}
res.end("退出成功");
});
});
module.exports = router;
koa中使用session
token
生成token:登录时,颁发token令牌
验证token:访问某些资源时,验证token
JWT
JWT(JSON Web Token)实现token机制:
HS256算法为对称加密,但不是所有服务器都需要颁发token的能力。当secretKey暴露存在安全隐患
koa使用token
npm i jsonwebtoken
const Koa = require('koa')
const KoaRouter = require('@koa/router')
const app = new Koa()
const jwt = require('jsonwebtoken')
const testRouter = new KoaRouter({ prefix: "/test" })
// 秘钥
const secretKey = '666'
testRouter.post('/register', (ctx, next) => {
// 颁发token
const payload = {name:'ccc',age:999}
const token = jwt.sign(payload,secretKey,{
expiresIn: 60
})
ctx.body = {
code: 200,
meg:'登录成功',
token
}
})
testRouter.get('/other', (ctx, next) => {
// 获取客户端携带过来的token
const authorization = ctx.header.authorization
console.log('authorization: ',authorization);
const token = authorization.replace('Bearer ','')
try {
// 验证token
const res = jwt.verify(token,secretKey)
ctx.body = {
res,
meg:'other页面'
}
} catch (error) {
ctx.body = {
msg: '无效token'
}
}
})
app.use(testRouter.routes())
app.use(testRouter.allowedMethods())
app.listen(8888, 'localhost', () => {
console.log(`http://localhost:8888`);
})
在header中携带token:
无效token:
非对称加密
私钥:颁发token令牌
公钥:验证tokrn令牌
1.在git-bash中使用openssl生成公钥秘钥文件
openssl
genrsa -out private.key 1024
rsa -in private.key -pubout -out public.key
2.使用公钥、秘钥
// 私钥
const privateKey = fs.readFileSync('./key/private.key')
// 公钥
const publicKey = fs.readFileSync('./key/public.key')
// 颁发token
const payload = {name:'ccc',age:999}
const token = jwt.sign(payload,privateKey,{
expiresIn: 60,
algorithm: 'RS256'
})
// 验证token
const res = jwt.verify(token,publicKey,{
algorithms:['RS256']
})
本地存储
localStorage与sessionStorage
localStorage 单个Item 最大5M
sessionStorage 单个Item 最大5M
Storage.length // 表示存储本地存储对象的个数
Storage.setItem('key','value')
Storage.getItem('key')
Storage.removeItem('key')
Storage.clear()
- localStorage与sessionStorage的API一致。
- localStorage会永久存储,除非手动删除
- sessionStorage关闭窗口重新打开会被删除
- sessionStorage在页面内跳转会被保留 a标签的target=‘_self’
- sessionStorage在页面外跳转会被删除 a标签的target=‘_blank’
存储值为对象形式
// 保存数据
localStorage.setItem('obj1',JSON.stringify(obj))
// 获取数据
JSON.parse( localStorage.getItem('obj1') )