文章目录
1. cookie
- cookie保存在客户端中,同时Cookie可以分为
内存Cookie和硬盘Cookie
。- 内存Cookie由浏览器维护,保存在内存中,浏览器关闭时Cookie就会消失,其存在时间是短暂的;
- 硬盘Cookie保存在硬盘中,有一个过期时间,用户手动清理或者过期时间到时,才会被清理;
- 如果判断一个cookie是内存cookie还是硬盘cookie呢?
没有设置过期时间
,默认情况下cookie是内存cookie,在关闭浏览器时会自动删除;有设置过期时间 (max-age=过期时间)
,并且过期时间不为0或者负数的cookie,是硬盘cookie,需要手动或者到期时,才会删除;
- 默认情况下的cookie是内存cookie,也称之为
会话cookie
,也就是在浏览器关闭时会自动被删除 - 可以通过设置expires或者max-age来设置过期的时间
expires
:设置的是Date.toUTCString(),设置格式是;expires=date-in-GMTString-format;max-age
:设置过期的秒钟,;max-age=max-age-in-seconds (例如一年为606024*365);
1.1 服务端cookie设置
- cookie验证
- 服务端设置cookie
- 客户端(游览器)获取服务器设置的cookie,并且做一个保存
- 在同一个作用域下进行访问(域名/路径), 会在动态携带cookie
- 服务器可以通过客户端携带的cookie验证用户的身份
const koa = require('koa');
const koaRouter = require('@koa/router');
const app = new koa()
/**
* @description:
* @param {type} 服务端设置cookie
* @param {type} 客户端(游览器)获取服务器设置的cookie,并且做一个保存
* @param {type} 在同一个作用域下进行访问(域名/路径), 会在动携带cookie
* @param {type} 服务器可以通过客户端携带的cookie验证用户的身份
* @return:
*/
const userRouter = new koaRouter({ prefix: '/users' })
userRouter.get('/login', (cxt, next) => {
// 服务器设置会话cookie
cxt.cookies.set('slogin', 'ikun', {
maxAge: 60 * 1000
})
cxt.body = '登录成功'
next()
})
userRouter.get('/list', (cxt, next) => {
// 当上个接口登录成功后 这个cookie会自动携带
const cookie = cxt.cookies.get('slogin')
console.log(cookie);
if (cookie) {
cxt.body = cookie
}
})
app.use(userRouter.routes())
app.listen(9000, () => {
console.log('服务器启动成功~');
})
- cookie是采用明文传输的因此安全性存在一定的问题
同时在发送HTTP请求时,发现游览器将我们的cookie都进行了携带(注意:游览器只会携带在当前请求的url中包含了该cookie中path值的cookie),并且是以key:value的形式进行表示的。多个cookie用;进行隔开。
1.2 cookie签名与加盐
- cookie中的签名基于session, Session 是另一种记录客户状态的机制,保存在服务器上。
- Session的工作流程:当浏览器访问服务器并发送第一次请求时,
服务器端会创建一个 session 对象,生成一个类似于 key,value 的键值对
,然后将 key(cookie)返回到浏览器(客户端),浏览器下次再访问时,携带 key(cookie),找到对应的 session(value),用户的信息都保存在 session 中
。
- 安装 npm install koa-session
const koa = require('koa');
const koaSession = require('koa-session');
const koaRouter = require('@koa/router');
const app = new koa()
// npm i koa-session
const session = koaSession({
key: 'sessionId',
httpOnly:true, // 不允许通过JS获取cookie
maxAge:5*1000, // 过期时间
rolling:true, // 每次响应时,刷新session的有效期
signed:true // 加密签名认证,防止数据被篡改,必传
},app)
app.keys=['aaa'] // 加盐操作 ,双层验证
app.use(session)
const userRouter = new koaRouter({ prefix: '/users' })
userRouter.get('/login', (cxt, next) => {
cxt.session.slogin='ikun'
cxt.body = '登录成功'
})
userRouter.get('/list', (cxt, next) => {
const cookie = cxt.session.slogin
console.log(cookie);
if (cookie) {
cxt.body = cookie
}else{
cxt.body='没有权限访问'
}
})
app.use(userRouter.routes())
app.listen(9000, () => {
console.log('服务器启动成功~');
})
1.3 cookie与session的区别
-
cookie 数据存放在客户端浏览器上,session 数据放在服务器上。
-
cookie 不是很安全,是明文传递的,所以存在安全性的问题;
-
session 会在一定时间内保存在服务器上。访问增多会占用服务器的性能,若要减轻服务器性能问题,应使用 cookie。
-
单个 cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 20 个 cookie。
-
对于浏览器外的其他客户端(比如iOS、Android),必须手动的设置cookie和session;
2. JWT token
-
一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。
-
JWT生成的Token由三部分组成:
-
header 用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。这也可以被表示成一个JSON对象。
- alg:采用的加密算法,默认是 HMAC SHA256(HS256),采用同一个密钥进行加密和解密;
- type:JWT,固定值,通常都写成JWT即可;
- 会通过base64Url算法进行编码;
-
payload
- 携带的数据,比如我们可以将用户的id和name放到payload中;
- 默认也会携带iat(issued at),令牌的签发时间;
- 我们也可以设置过期时间:exp(expiration time);
-会通过base64Url算法进行编码
-
signature
- 设置一个
secretKey
,通过将前两个的结果合并后进行HS256的算法; - HMACSHA256(base64Url(header)+.+base64Url(payload), secretKey);
- 但是如果secretKey暴露是一件非常危险的事情,因为之后就可以模拟颁发token,也可以解密token;
- 设置一个
-
前后端交互图理解
-
POSTMAN 设置token全局共享
2.1 HS256对称加密
- HS256 (带有 SHA-256 的 HMAC 是一种对称算法, 双方之间仅共享一个 密钥。由于使用相同的密钥生成签名和验证签名, 因此必须注意确保密钥不被泄密
const koa = require('koa');
const jwt = require('jsonwebtoken');
const koaRouter = require('@koa/router');
const app = new koa()
// npm i jsonwebtoken
const userRouter = new koaRouter({ prefix: '/users' })
userRouter.get('/login', (cxt, next) => {
// 1. 颁发token
const payload = { name: 'admin', password: 123456 }
const secretKey = "aaaaaaaaaaaaaa"
const token = jwt.sign(payload, secretKey, {
expiresIn:30
})
cxt.body={
code:200,
token:token,
message:'登录成功'
}
})
userRouter.get('/list', (cxt, next) => {
// 获取客户端携带过来的token
const authorization=cxt.headers.authorization
const token=authorization.replace('Bearer','')
console.log(token);
// 2. 验证token
try {
const result=jwt.verify(token,escretkey)
console.log(result);
} catch (error) {
cxt.body = 'token过期,没有权限访问,请重新登录'
}
})
app.use(userRouter.routes())
app.listen(9000, () => {
console.log('服务器启动成功~');
})
2.2 RS256非对称加密
- RS256 (采用SHA-256 的 RSA 签名) 是一种非对称算法, 它使用公共/私钥对:标识提供方采用
私钥生成签名
, JWT 的使用方获取公钥以验证签名
。由于公钥 (与私钥相比) 不需要保护, 因此大多数标识提供方使其易于使用方获取和使用 (通常通过一个元数据URL) - 用非对称加密,RS256:
- 私钥(private key):用于发布令牌;
- 公钥(public key):用于验证令牌;
- 使用git Bash生成一对私钥和公钥
openssl
genrsa -out private.key 2048
rsa -in private.key -pubout -out public.key
const koa = require('koa');
const jwt = require('jsonwebtoken');
const fs = require('fs');
const koaRouter = require('@koa/router');
const app = new koa()
const pubilcKey = fs.readFileSync('./keys/public.key')
const reivateKey = fs.readFileSync('./keys/private.key')
const userRouter = new koaRouter({ prefix: '/users' })
userRouter.get('/login', (cxt, next) => {
// 1. 颁发token
const payload = { name: 'admin', password: 123456 }
const token = jwt.sign(payload, reivateKey, {
// 修改加密方式 HS256改为RS256加密
expiresIn: 60, algorithm: 'RS256'
})
cxt.body = {
code: 200,
token: token,
message: '登录成功'
}
})
userRouter.get('/list', (cxt, next) => {
// 获取客户端携带过来的token
const authorization = cxt.headers.authorization
const token = authorization.replace('Bearer', '')
// 2. 验证token
try {
const result = jwt.verify(token, pubilcKey, {algorithms: ['RS256'] })
console.log(result);
} catch (error) {
cxt.body = 'token过期,没有权限访问,请重新登录'
}
})
app.use(userRouter.routes())
app.listen(9000, () => {
console.log('服务器启动成功~');
})