Bootstrap

cookie与jwt解析

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 是另一种记录客户状态的机制,保存在服务器上。
  1. 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的区别

  1. cookie 数据存放在客户端浏览器上,session 数据放在服务器上。

  2. cookie 不是很安全,是明文传递的,所以存在安全性的问题;

  3. session 会在一定时间内保存在服务器上。访问增多会占用服务器的性能,若要减轻服务器性能问题,应使用 cookie。

  4. 单个 cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 20 个 cookie。

  5. 对于浏览器外的其他客户端(比如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;
  • JWT原理文章参考

  • 前后端交互图理解
    在这里插入图片描述

  • 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生成一对私钥和公钥
  1. openssl
  2. genrsa -out private.key 2048
  3. 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('服务器启动成功~');
})
;