首页 > 其他分享 >JWT原理

JWT原理

时间:2024-07-07 13:30:48浏览次数:13  
标签:const string ctx segments JWT token 原理

JWT

  • JWT(json web token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。
  • JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。比如用在用户登录上。
  • 因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名

主要应用场景

  • 身份认证在这种场景下,一旦用户完成了登陆,在接下来的每个请求中包含JWT,可以用来验证用户身份以及对路由,服务和资源的访问权限进行验证。
  • 信息交换在通信的双方之间使用JWT对数据进行编码是一种非常安全的方式,由于它的信息是经过签名的,可以确保发送者发送的信息是没有经过伪造的

JWT的结构

JWT包含了使用.分隔的三部分

  • Header 头部
  • Payload 负载
  • Signature 签名

Header

在header中通常包含了两部分:token类型和采用的加密算法。

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

接下来对这部分内容使用Base64Url编码组成了JWT结构的第一部分。

Payload

负载就是存放有效信息的地方。这个名字像是指货车上承载的货物,这些有效信息包含三个部分

  • 标准中注册的声明
  • 公共的声明
  • 私有的声明
{ "name": "hs"} 

上述的负载需要经过Base64Url编码后作为JWT结构的第二部分

Signature

  • 创建签名需要使用编码后的header和payload以及一个秘钥

  • 使用header中指定签名算法进行签名

  • 例如如果希望使用HMAC SHA256算法,那么签名应该使用下列方式创建

    HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret) 
    
  • 签名用于验证消息的发送者以及消息是没有经过篡改的

  • 完整的JWT 完整的JWT格式的输出是以. 分隔的三段Base64编码

  • 密钥secret是保存在服务端的,服务端会根据这个密钥进行生成token和验证,所以需要保护好。

如何使用JWT

  1. 当用户使用它的认证信息登陆系统之后,会返回给用户一个JWT

  2. 用户只需要本地保存该token(通常使用local storage,也可以使用cookie)即可

  3. 当用户希望访问一个受保护的路由或者资源的时候,通常应该在Authorization头部使用Bearer模式添加JWT,其内容看起来是下面这样

    Authorization: Bearer <token>
    
  4. 因为用户的状态在服务端的内存中是不存储的,所以这是一种无状态的认证机制

  5. 服务端的保护路由将会检查请求头Authorization中的JWT信息,如果合法,则允许用户的行为。

  6. 由于JWT是自包含的,因此减少了需要查询数据库的需要

  7. JWT的这些特性使得我们可以完全依赖其无状态的特性提供数据API服务,甚至是创建一个下载流服务。

  8. 因为JWT并不使用Cookie的,所以你可以使用任何域名提供你的API服务而不需要担心跨域资源共享问题(CORS)

image-20240706231947256

JWT实战

server.js

const Koa = require('koa');
const app = new Koa();
const Router = require('koa-router');
const router = new Router();
const bodyParser = require('koa-bodyparser');
const jwt = require('./jwt-simple');
const secretKey = 'jwt-secret';
app.use(bodyParser());
router.get('/login', async (ctx) => {
  ctx.body = `
    <form action="/login" method="post">
      <input type="text" name="username" />
      <input type="submit" value="提交" />
    </form>
  `;
});
const expirationTime = 60 * 60 * 24; // 过期时间为1天(单位为秒)
const expirationDate = Math.floor(Date.now() / 1000) + expirationTime; // 计算过期时间戳
router.post('/login', async ctx => {
  const { username } = ctx.request.body;
  const token = jwt.encode({ username,exp: expirationDate }, secretKey);
  ctx.body = { token };
});
router.get('/user', async ctx => {
  const authorizationHeader = ctx.request.headers.authorization;
  if (authorizationHeader && authorizationHeader.startsWith('Bearer ')) {
    const token = authorizationHeader.substring(7);
    try {
      const decoded = jwt.decode(token, secretKey);
      ctx.body = decoded.username;
    } catch (error) {
      ctx.status = 401;
      ctx.body = 'Invalid token';
    }
  } else {
    ctx.status = 401;
    ctx.body = 'Missing token';
  }
});
app.use(router.routes());
app.listen(3000, () => {
  console.log('Server is running at http://localhost:3000');
});
curl -H "Authorization: Bearer token" http://localhost:3000/user

jwt-simple.js

jwt-simple.js

const crypto = require('crypto');

/**
 * 编码JWT令牌
 * @param {Object} payload 负载数据
 * @param {string} key 密钥
 * @returns {string} 编码后的JWT令牌
 */
function encode(payload, key) {
    let header = { type: 'JWT', alg: 'sha256' }; // 声明类型和算法
    var segments = []; // 声明一个数组
    segments.push(base64urlEncode(JSON.stringify(header))); // 对header进行base64编码
    segments.push(base64urlEncode(JSON.stringify(payload))); // 对负载进行base64编码
    segments.push(sign(segments.join('.'), key)); // 加入签名
    return segments.join('.');
}

/**
 * 生成签名
 * @param {string} input 输入数据
 * @param {string} key 密钥
 * @returns {string} 签名
 */
function sign(input, key) {
    return crypto.createHmac('sha256', key).update(input).digest('base64');
}

/**
 * 解码JWT令牌
 * @param {string} token JWT令牌
 * @param {string} key 密钥
 * @returns {Object} 解码后的负载数据
 * @throws {Error} 如果验证失败或令牌过期,则抛出错误
 */
function decode(token, key) {
    var segments = token.split('.');
    var headerSeg = segments[0];
    var payloadSeg = segments[1];
    var signatureSeg = segments[2];
    var payload = JSON.parse(base64urlDecode(payloadSeg));
    if (signatureSeg != sign([headerSeg, payloadSeg].join('.'), key)) {
        throw new Error('verify failed');
    }
    if (payload.exp && Date.now() > payload.exp * 1000) {
        throw new Error('Token expired');
    }
    return payload;
}

/**
 * Base64 URL编码
 * @param {string} str 输入字符串
 * @returns {string} 编码后的字符串
 */
function base64urlEncode(str) {
    return Buffer.from(str).toString('base64');
}

/**
 * Base64 URL解码
 * @param {string} str 编码的字符串
 * @returns {string} 解码后的字符串
 */
function base64urlDecode(str) {
    return Buffer.from(str, 'base64').toString();
}

module.exports = {
    encode,
    decode
};

标签:const,string,ctx,segments,JWT,token,原理
From: https://blog.csdn.net/qq_40588441/article/details/140244999

相关文章

  • Java信号量semaphore的原理与使用方法
    Semaphore的基本概念在Java中,Semaphore是位于java.util.concurrent包下的一个类。它的核心就是维护了一个许可集。简单来说,就是有一定数量的许可,线程需要先获取到许可,才能执行,执行完毕后再释放许可。那么,这个许可是什么呢?其实,你可以把它想象成是对资源的访问权。比如,有5个......
  • AQS原理
    AQS1.引言首先来看看,如果用java并发包下的ReentrantLock来加锁和释放锁,是个什么样的感觉?这个学过java的同学应该都会吧,毕竟是java并发基本API的使用,我们直接看一下代码:一个Lock对象,然后加锁和释放锁你这时可能会问,这个跟AQS有啥关系?关系大了去了!因为java并发包下很多API都......
  • 【SpringBoot】SpringBoot自动装配原理
    在上一篇文章中,讲述了SpringBoot核心启动流程源码解析其中,主要是构造方法和run方法的处理,本篇接着准备上下文环境后续,讲述是如何将springboot是如何完成自动装配,主线其实就是什么时候完成对主类的加载,也即对SpringBootApplication类加载到IOC容器中什么时候完成对Spring......
  • 【C/C++ new/delete和malloc/free的异同及原理】
    new/delete和malloc/free都是用于在C++(以及C语言在malloc/free的情况下)中动态申请和释放内存的机制,但它们之间存在一些显著的异同点。以下是对这两组函数/运算符的异同点的详细分析:相同点目的相同:两者都用于在堆(heap)上动态地分配和释放内存。手动管理:无论是new/delete还是......
  • 计算机组成原理复习与预习指南~持续更新~
    计算机组成原理是计算机科学领域的基石,理解它不仅能帮助你更好地掌握计算机的工作原理,还能为你在编程、系统设计和性能优化方面提供强大的理论支持。本文将带你深入探索计算机的组成,从CPU、存储器到系统总线和I/O系统,全面解析各个部分的工作原理和实际应用。同时,我们也会结......
  • 数据库原理之并发控制的基本概念
    我们今天继续来看数据库原理,我们简单讲讲数据库的并发控制。并发控制的定义并发控制是为了保证事务的隔离性和一致性,数据库管理系统需要对并发操作进行正确调度。并发控制的主要技术有:、时间戳、乐观控制法、多版本并发控制等。并发操作带来的数据不一致性主要有以下三点:......
  • 天气学原理复习整理(南信大)
    第0章绪论天气学的含义:天气学原理是研究不同尺度的天气系统和天气现象发生发展及其变化的基本规律,并利用这些规律来预测未来天气的科学。天气系统:在时间或者空间上可以与其他系统区别开来的一个实体。在系统与系统之间存在着界面,而各系统的物理量可以通过界面交换。天气过......
  • 每天一道Java面试题系列之--Spring事务的实现原理
    面试题描述Spring事务的实现原理,并解释以下概念:PlatformTransactionManager 接口的作用是什么?什么是事务的传播行为?声明式事务和编程式事务有什么区别?@Transactional 注解是如何工作的?题解1. PlatformTransactionManager 接口PlatformTransactionManager是Spring事务......
  • 站在架构师角度:深入剖析Spring事务管理底层原理
    摘要Spring框架的事务管理是企业级应用开发中的一个核心特性,它为不同的事务使用场景提供了统一的抽象和实现。本文从架构师的角度出发,深入探讨Spring事务管理的底层原理,包括其设计哲学、核心组件、以及事务传播行为等。1.事务管理概述事务是数据库操作中的一个基本概念,它保......
  • springboot 自动配置原理
    @SpringBootApplication发现是一个复合注解@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan由三个注解组合而来@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfigurat......