资讯专栏INFORMATION COLUMN

cookie✘session✘jwt

sarva / 896人阅读

cookie✘session✘jwt 写在前面
PS:已经有很多文章写过这些东西了,我写的目的是为了自己的学习。所学只是为了更好地了解用户登录鉴权问题。

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

什么是无状态?

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

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

为了保证登录信息以及状态信息能够传递下去,就引入了其他机制

session和cookie Cookie

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

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

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

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

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

Session

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

具体的过程如下:

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

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

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

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}}

当你退出时,清空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发送给客户端

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

(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中包含的信息对象

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/94670.html

相关文章

  • 详解 CookieSession,Token

    摘要:由于是存在客户端上的,所以浏览器加入了一些限制确保不会被恶意使用,同时不会占据太多磁盘空间。签名是对前两部分的签名,防止数据被篡改。的作用最开始的初衷是为了实现授权和身份认证作用的,可以实现无状态,分布式的应用授权。 前言 无状态的HTTP协议 很久很久之前, Web基本都是文档的浏览而已。既然是浏览, 作为服务器, 不需要记录在某一段时间里都浏览了什么文档, 每次请求都是一个新的HT...

    Allen 评论0 收藏0
  • JWT、OAuth 2.0、session 用户授权实战

    摘要:为用户提供授权以允许用户操作非公开资源,有很多种方式。具体的代码根据不同的授权方案而有所不同。使用授权原理利用来验证用户,有两种机制实现。使用来实现用户授权主要用于签发如果有将异步的签名。注意这里的与之前用于签发的应该是同一个。 在很多应用中,我们都需要向服务端提供自己的身份凭证来获得访问一些非公开资源的授权。比如在一个博客平台,我们要修改自己的博客,那么服务端要求我们能够证明 我是...

    Jochen 评论0 收藏0
  • JWT、OAuth 2.0、session 用户授权实战

    摘要:为用户提供授权以允许用户操作非公开资源,有很多种方式。具体的代码根据不同的授权方案而有所不同。使用授权原理利用来验证用户,有两种机制实现。使用来实现用户授权主要用于签发如果有将异步的签名。   在很多应用中,我们都需要向服务端提供自己的身份凭证来获得访问一些非公开资源的授权。比如在一个博客平台,我们要修改自己的博客,那么服务端要求我们能够证明 我是我 ,才会允许我们修改自己的...

    zhaot 评论0 收藏0
  • JWT必知必会

    摘要:最近,项目的安全认证机制全面采用。为了伸缩性考虑,采用机制,必然面临着应用状态的问题,而且必然牵涉到的复制。为了安全性考虑,机制仅验证时天然对免疫。若有可能,使用标志。采用来防止这是因为,在站点上发起向站点的请求时,站点的同样会被发送给。 最近,项目的安全认证机制全面采用JWT。现在,趁整个工作基本告一段落之际,将一些知识点总结一下发布出来。 为什么要迁移? 原因很简单,就以下几点: ...

    张金宝 评论0 收藏0
  • 前端应该知道的web登录

    摘要:客户端发起非登录请求时,服务端通过中的找到对应的来知道此次请求是谁发出的。数量随着登录用户的增多而增多,存储会增加很多。还记得在上家公司做全干工程师的时候,基本从页面写到运维,当时做登录这块的时候,被session、cookie、token各种概念差点整蒙圈了,上网查询相关概念,发现很多人都是类似的疑惑,比如:showImg(https://user-gold-cdn.xitu.io/201...

    NervosNetwork 评论0 收藏0

发表评论

0条评论

sarva

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<