98 # jwt

简介: 98 # jwt

什么是 jwt

JSON WEB TOKEN (jwt) 是目前最流行的跨域身份验证解决方案。

解决问题:session 不支持分布式框架,无法支持横向扩展,只能通过数据库来保存会话数据实现共享,如果持久层失效就会出现认证失败。

优点:服务器不保存任何会话数据,即服务器变为无状态,使其更容易扩展。

jwt 组成

Header 头部

header 典型的由两部分组成:token 的类型(“JWT”)和算法名称(比如:HMAC SHA256或者RSA等等)。

{
    'typ': "JWT",
    'alg': "HS256"
}

将头部进行 base64 加密(该加密是可以对称解密的),得到 JWT 的第一部分

Payload 负载、负荷

它包含声明(要求),声明是关于实体(通常是用户)和其他数据的声明。

声明有三种类型: registered(标准中注册的声明), public(公共的声明)和 private(私有的声明)。

  • Registered claims: 一组预定义的声明,它们不是强制的,但是推荐。
  • Public claims: 可以随意定义。
  • Private claims: 用于在同意使用它们的各方之间共享信息,并且不是注册的或公开的声明。

jwt 规定了 7 个官方字段(标准中注册的声明 (建议但不强制使用))

iss (issuer) jwt 签发人
exp (expiration time) jwt 过期时间
sub (subject) 主题 / jwt 所面向的用户
aud (audience) 受众 / 接收 jwt 的一方
nbf (Not Before) jwt 生效时间
iat (Issued At) jwt 签发时间
jti (JWT ID) 编号 / jwt 唯一身份标识

例子:

{
    "sub": '1234567890',
    "name": 'kaimo',
    "admin": true
}

对 payload 进行 Base64 编码就得到 JWT 的第二部分

Signature

对前两个部分的签名,防止数据篡改。

需要编码过的 header、编码过的 payload 连接组成的字符串,然后通过 header 中指定的签名算法进行加盐 secret 组合加密,然后就构成了 jwt 的第三部分。

例子:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

Base64URL 算法

Base64 有三个字符:+/=,在 URL 里面有特殊含义,所以要被替换掉:

  • = 被省略
  • + 替换成 -
  • / 替换成 _

这个就是 Base64URL 算法。

jwt-simple 的使用

实现个登录跟检测是否登录功能

npm i jwt-simple koa-bodyparser

这里使用简单点的 jwt-simple,强一点的可以使用 jwtwebtoken

const Koa = require("koa");
const Router = require("@koa/router");
const bodyparser = require("koa-bodyparser");
const jwt = require("jwt-simple");
const app = new Koa();
let router = new Router();
app.use(bodyparser());
app.use(router.routes());
router.post("/login", async (ctx, next) => {
    let { username, password } = ctx.request.body;
    if (username === "admin" && password === "123456") {
        let token = jwt.encode(username, "kaimo");
        ctx.body = {
            err: 0,
            username,
            token
        };
    }
});
router.get("/validate", async (ctx, next) => {
    let authorization = ctx.headers.authorization;
    try {
        let r = jwt.decode(authorization, "kaimo");
        ctx.body = {
            err: 0,
            username: r
        };
    } catch (error) {
        ctx.body = {
            err: 1,
            message: error
        };
    }
});
app.listen(3000);
console.log("Server running at http://127.0.0.1:3000/");

控制台可以访问:

curl -v -X POST --data "username=admin&password=123456" http://localhost:3000/login

我这里直接使用的 postman

http://localhost:3000/login

访问 http://localhost:3000/validate

实现自己的 jwt

这个 base64urlUnescape 方法反解 base64 的方法,可以参考 jwt-simple 里的实现,是规定的解法。

下面实现自己的 jwt

const Koa = require("koa");
const Router = require("@koa/router");
const bodyparser = require("koa-bodyparser");
const crypto = require("crypto");
const app = new Koa();
let router = new Router();
app.use(bodyparser());
app.use(router.routes());
let kaimoJwt = {
    toBase64Url(base64) {
        return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
    },
    toBase64(content) {
        return Buffer.from(JSON.stringify(content)).toString("base64");
    },
    sign(content, secret) {
        return this.toBase64Url(crypto.createHmac("sha256", secret).update(content).digest("base64"));
    },
    encode(payload, secret) {
        console.log("进入 kaimo-jwt--encode--->", payload, secret);
        let header = this.toBase64Url(
            this.toBase64({
                typ: "JWT",
                alg: "HS256"
            })
        );
        let content = this.toBase64Url(this.toBase64(payload));
        let sign = this.sign([header, content].join("."), secret);
        return [header, content, sign].join(".");
    },
    base64urlUnescape(str) {
        str += new Array(5 - (str.length % 4)).join("=");
        return str.replace(/\-/g, "+").replace(/_/g, "/");
    },
    decode(token, secret) {
        console.log("进入 kaimo-jwt--decode--->", token, secret);
        let [header, content, sign] = token.split(".");
        console.log("header---->", header);
        console.log("content---->", content);
        console.log("sign---->", sign);
        let newSign = this.sign([header, content].join("."), secret);
        console.log("newSign---->", newSign);
        if (sign === newSign) {
            // 将 base64 转化成字符串
            return JSON.parse(Buffer.from(this.base64urlUnescape(content), "base64").toString());
        } else {
            throw new Error("token 被篡改");
        }
    }
};
router.post("/login", async (ctx, next) => {
    let { username, password } = ctx.request.body;
    if (username === "admin" && password === "123456") {
        let token = kaimoJwt.encode(username, "kaimo");
        ctx.body = {
            err: 0,
            username,
            token
        };
    }
});
router.get("/validate", async (ctx, next) => {
    let authorization = ctx.headers.authorization;
    try {
        let r = kaimoJwt.decode(authorization, "kaimo");
        ctx.body = {
            err: 0,
            username: r
        };
    } catch (error) {
        ctx.body = {
            err: 1,
            message: error
        };
    }
});
app.listen(3000);
// eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.ImFkbWluIg.prJEZUHxS0PtLnjZ0RwhUyQ-4HkANXZVAlIHU3ZNh7k
console.log("Server running at http://127.0.0.1:3000/");

效果也是一样的

目录
相关文章
|
6月前
|
存储 JSON 安全
JWT 还能这样的去理解嘛??
JWT (JSON Web Token) 是目前最流行的跨域认证解决方案,是一种基于 Token 的认证授权机制。从 JWT 的全称可以看出,JWT 本身也是 Token,一种规范化之后的。JWT 自身包含了身份验证所需要的所有信息,因此,我们的服务器不需要存储 Session 信息。这显然增加了系统的可用性和伸缩性,大大减轻了服务端的压力。可以看出,。并且, 使用 JWT 认证可以攻击,因为 JWT 一般是存在在中,使用 JWT 进行身份验证的过程中是的。
211 1
|
4月前
|
存储 JSON 算法
JWT
【7月更文挑战第5天】
48 0
|
5月前
|
存储 JSON 算法
12.Jwt
12.Jwt
30 0
|
前端开发
什么是JWT?深入理解JWT从原理到应用(下)
什么是JWT?深入理解JWT从原理到应用(下)
108 0
|
6月前
|
JSON 算法 数据库
JWT 是什么
JWT 是什么
|
6月前
|
存储 JSON 算法
什么是JWT?
什么是JWT?
68 0
|
6月前
|
存储 JSON 算法
快速了解什么是jwt及如何使用jwt
快速了解什么是jwt及如何使用jwt
179 0
|
11月前
|
存储 JSON 安全
了解什么是JWT
了解什么是JWT
66 0
|
11月前
|
JSON 数据格式
jwt->jwt简介,jwt工具类,jwt集进成spa项目
jwt->jwt简介,jwt工具类,jwt集进成spa项目
82 0
|
JSON 算法 前端开发
什么是JWT?深入理解JWT从原理到应用(上)
什么是JWT?深入理解JWT从原理到应用(上)
1735 0