cookie✘session✘jwt

cookie✘session✘jwt

写在前面

PS:已经有不少文章写过这些东西了,我写的目的是为了本身的学习。所学只是为了更好地了解用户登陆鉴权问题。

咱们都知道HTTP是一个无状态的协议javascript

什么是无状态?html

用http协议进行两台计算机交互时,不管是服务器仍是浏览器端,http协议只负责规定传输格式,你怎么传输,我怎么接受怎么返回。它并无记录你上次访问的内容,你上次传递的参数是什么,它无论的。前端

回到咱们要解决的问题,就是用户登陆到了一个网站(index.html),而后点击主页上的某一个超连接跳转到其余页面(another.html),这个时候你在another.html页面就没有了登录状态。这样意味着咱们每次跳转一个页面都要进行一次登录操做,这是极其不合理的。java

为了保证登陆信息以及状态信息可以传递下去,就引入了其余机制git

session和cookie

Cookie

(1)cookie是实际存在的,存在于客户端,用户可见可修改,不安全。github

(2)cookie在一个域名下是全局的,只要设置path为/,便可从该域名下的任意页面读取cookie中的信息。web

(3)为了安全,HttpOnly设置为true,这样能够必定程度上的预防XSS(跨站脚本攻击)redis

(4)浏览器禁用cookie以后,这种状况下会使用url重写的技术来进行会话跟踪,即在url后面加上sid=xxx参数。算法

大多数应用都是基于cookie来实现session跟踪的。mongodb

Session

session是一种机制,并不实际存在,它由服务器负责管理。关闭浏览器以后,session就会丢失。

具体的过程以下:

(1)客户端第一次发送请求到服务器,服务器生成一个惟一的sessionId,一个sessionId对应一个用户,该sessionId能够存放在Redis或者mongodb中,具体存放在哪里看我的选择

(2)后端将该sessionId放到响应头的Set-Cookie字段,返给前端。

响应头

(3)前端记下该sessionId并放到cookie字段,以后每次客户端请求服务器时都会在请求头带上cookie字段,服务端根据sessionId来获取具体信息(好比TTL,过时时间,用户id)

image

Koa2中使用session

首先固然是引入包了啊,这里选择了koa-session2`。koa-session2`已经帮你作好了全部,使用起来至关简单,方便快速开发。

const Koa = require("koa")
const app = new Koa()
const session = require("koa-session2")

app.use(session({
    stort: new RedisStore(), //存放session的地方,我这里选择放到redis里
    key: "SESSION_ID"
}))

new RedisStore()又是什么呢?其实查看koa-session2的git仓https://github.com/Secbone/koa-session2就能知道

如下来自官方git仓:

const Redis = require("ioredis");
const { Store } = require("koa-session2");

class RedisStore extends Store {
    constructor() {
        super();
        this.redis = new Redis(); // 链接redis
    }

    async get(sid, ctx) { 
        let data = await this.redis.get(`SESSION:${sid}`);
        return JSON.parse(data);
    }

    async set(session, { sid =  this.getID(24), maxAge = 1000000 } = {}, ctx) {
        try {
            // Use redis set EX to automatically drop expired sessions
            // 设置redis的Ex 以自动丢弃过时的session
            await this.redis.set(`SESSION:${sid}`, JSON.stringify(session), 'EX', maxAge / 1000);
        } catch (e) {}
        return sid;
    }

    async destroy(sid, ctx) { // 删除redis中的数据
        return await this.redis.del(`SESSION:${sid}`);
    }
}

module.exports = RedisStore;

接下来就是判断登录,以及将须要的信息写入session

let sid = ctx.cookies.get("SESSION_ID") // 得到cookie中的sid

ctx.session.myinfo = {a: 1, b: 2} //将一个数据对象放到session中

// 最后的结果就是:

// redis中的键为SESSION:sid

// 值为{myinfo: {a: 1, b: 2}}

redis

当你退出时,清空cookie和session便可

ctx.cookies.set("SESSION_ID", "")
ctx.session = null

JWT

简答认识JWT

让咱们来看看重头戏JWT,全称JSONWebToken,是一种目前较为流行的验证方式。

JWT由三部分组成,第一部分咱们称它为头部(header),

//header 
{
    'typ': 'JWT', // 类型
    'alg': 'HS256' // 加密算法
}
// 对其base64 获得了第一个部分

第二部分咱们称其为载荷(payload, 相似于飞机上承载的物品)

// payload 存放有效信息的地方 好比userId
{
  "id": "1234567890",
  "name": "John Doe",
  "isMan": true
}
// 对其base64 获得第二个部分

第三部分是签证(signature).

// 将base64后的header和base64后的payload使用.链接组成新的字符串,而后使用header中声明的加密方式对其进行加盐secret组合加密,获得了第三个部分

将三部分用.链接成一个完整的字符串,获得了最终的jwt。

注意

  • 不该该在jwt的payload部分存放敏感信息,由于该部分是客户端可解密的部分。
  • 保护好secret私钥,该私钥很是重要。
  • 若是能够,请使用https协议

具体的过程以下:

(1)客户端第一次发送请求到服务端,服务器验证用户信息

(2)服务端生成一个token发送给客户端

token

(3)客户端保存token,以后每次请求时带上这个token

image

(4)服务端验证token,返回数据。

与session的过程是相似的,可是缺乏了将jwt保存到服务端,这样便于扩展,不会由于登陆到不一样的服务器致使session没法共享。

Koa2中使用jwt

第一步固然仍是下包。。npm install jsonwebtoken

const jwt = require("jsonwebtoken")

服务端生成token,并返给前端

// 生成token
const token = jwt.sign({role: user.role, id: user._id}, key, {expiresIn: "1 days"}) // 第一个参数为负载的信息,第二个参数为secret,第三个参数我是过时时间

// 返回前端
ctx.body = {
    token: token
}

客户端以后发起请求,应该带上token字段,将其放在authorization请求头字段或者以query的方式。

if(ctx.header.authorization && ctx.headers.authorization.split(' ')[0] === "Bearer") {
        token = ctx.header.authorization.split(' ')[1]
    } else if(ctx.query && ctx.query.token) {
        token = ctx.query.token
    }

而后服务端验证token,进行相应的处理返回数据。

// 解密token 通常使用jwt.verify不适用jwt.decode
let decoded = jwt.verify(token, key) // 获得token中包含的信息对象
相关文章
相关标签/搜索