JWT(JSON Web Token)简介及实现
JWT(JSON Web Token):是一个开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间作为Json对象安全地传输信息。由于此信息是经过数字签名的,因此可以被验证和信任。可以使用HMAC SHA256或RSA等对JWT进行签名。
JWT的组成:它是一个很长的字符串,中间用点(.)分隔成三个部分。它的三个部分依次是:Header(头部)、Payload(载荷)、Signature(签名)。JWT默认是不加密的。
Header:是一个Json对象,描述JWT的元数据,例子如下:alg属性表示签名的算法,默认是HMAC SHA256,写成HS256,也可使用RSA;typ属性表示这个令牌(token)的类型,JWT令牌统一写为JWT;id属性是用户自定义的。最后将此Json对象使用base64url编码成字符串。
{"alg": "HS256","typ": "JWT","id": "fengbingchun"
}
Payload:也是一个Json对象,用来存放实际需要传递的数据。JWT规定了7个官方字段,供选用:iss(Issuer):签发人;exp(Expiration Time):过期时间;sub(Subject):主题;aud(Audience):受众;nbf(Not Before):生效时间;iat(Issued At):签发时间;jti(JWT ID):编号。除了官方字段,你还可以在这个部分定义私有字段。最后此Json对象也要使用base64url编码成字符串。例子如下:
{"csdn": "https://blog.csdn.net/fengbingchun","github": "https://github.com//fengbingchun"
}
Signature:是对前两部分的签名,防止数据篡改。首先需要指定一个密钥(secret),然后使用Header里面指定的签名算法(默认是HMAC SHA256),按照以下的方式产生签名:算出签名后,也需要把此签名通过base64url编码成字符串。最后把Header、Payload、Signature三个部分编码成的字符串拼成一个字符串,每个部分之间用”点”(.)分隔,形式如xxxx.yyyy.zzzz。
HMACSHA256(base64urlEncode(header) + "." + base64urlEncode(payload), secret)
base64url和base64区别:base64有三个字符+、/和=,在URL里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_,这就是base64url。
一般此JWT会放在HTTP请求的头信息Authorization字段里:
Authorization: Bearer <token>
注:以上内容主要来自网络整理,主要参考:
1. https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
2. https://jwt.io/introduction/
3. https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32
以下是代码实现:
Header和Payload内容如上所示,secret值为:"1234567890+-!@#$%^&*x()_=QF{></?",代码段如下:
int test_jwt()
{// encode headerconst char* header = "{\"alg\":\"HS256\",\"typ\":\"JWT\",\"id\":\"fengbingchun\"}";int length_header = strlen(header);int length_encoded_header = (length_header + 2) / 3 * 4;std::unique_ptr<char[]> encoded_header(new char[length_encoded_header]);int ret = base64url_encode((const unsigned char*)header, length_header, encoded_header.get());if (ret != BASE64_OK) {fprintf(stderr, "fail to encode header: %s\n", header);return -1;}fprintf(stdout, "encoded header: %s\n", encoded_header.get());// encode payloadconst char* payload = "{\"csdn\":\"https://blog.csdn.net/fengbingchun\",\"github\":\"https://github.com//fengbingchun\"}";int length_payload = strlen(payload);int length_encoded_payload = (length_payload + 2) / 3 * 4;std::unique_ptr<char[]> encoded_payload(new char[length_encoded_payload]);ret = base64url_encode((const unsigned char*)payload, length_payload, encoded_payload.get());if (ret != BASE64_OK) {fprintf(stderr, "fail to encode payload: %s\n", payload);return -1;}fprintf(stdout, "encoded payload: %s\n", encoded_payload.get());// signaturestd::string buffer;buffer.append(encoded_header.get(), strlen(encoded_header.get()));buffer.append(".");buffer.append(encoded_payload.get(), strlen(encoded_payload.get()));//const unsigned char key[] = { // 32 bytes// 0xee, 0xbc, 0x1f, 0x57, 0x48, 0x7f, 0x51, 0x92, 0x1c, 0x04, 0x65, 0x66,// 0x5f, 0x8a, 0xe6, 0xd1, 0x65, 0x8b, 0xb2, 0x6d, 0xe6, 0xf8, 0xa0, 0x69,// 0xa3, 0x52, 0x02, 0x93, 0xa5, 0x72, 0x07, 0x8f };const char key[] = { // 32 bytes'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '+', '-','!', '@', '#', '$', '%', '^', '&', '*', 'x', '(', ')', '_','=', 'Q', 'F', '{', '>', '<', '/', '?' };std::unique_ptr<unsigned char[]> signature(new unsigned char[EVP_MAX_MD_SIZE]);HMAC_CTX* ctx = HMAC_CTX_new();HMAC_CTX_reset(ctx);const EVP_MD* engine = EVP_sha256();unsigned int length_signature;HMAC_Init_ex(ctx, key, sizeof(key), engine, nullptr);HMAC_Update(ctx, reinterpret_cast<const unsigned char*>(buffer.c_str()), buffer.length());HMAC_Final(ctx, signature.get(), &length_signature);HMAC_CTX_free(ctx);// encode signatureint length_encoded_signature = (length_signature + 2) / 3 * 4;std::unique_ptr<char[]> encoded_signature(new char[length_encoded_signature]);ret = base64url_encode(signature.get(), length_signature, encoded_signature.get());if (ret != BASE64_OK) {fprintf(stderr, "fail to encode signature\n");return -1;}fprintf(stdout, "encoded signature: %s\n", encoded_signature.get());buffer.append(".");buffer.append(encoded_signature.get(), strlen(encoded_signature.get()));fprintf(stdout, "jwt result: %s\n", buffer.c_str());return 0;
}
上面的HMAC-SHA256是调用OpenSSL的接口实现的,也可调用bearssl接口实现,代码段如下:
br_hmac_key_context key_ctx;br_hmac_context ctx;br_hmac_key_init(&key_ctx, &br_sha256_vtable, key, sizeof(key));br_hmac_init(&ctx, &key_ctx, 0);size_t length_signature = br_hmac_size(&ctx);br_hmac_update(&ctx, buffer.c_str(), buffer.length());std::unique_ptr<unsigned char[]> signature(new unsigned char[length_signature]);size_t length_signature2 = br_hmac_out(&ctx, signature.get());
采用OpenSSL和bearssl结果完全一致,执行结果如下所示:
将上面的Header、Payload、secret值填入jwt.io,得到的结果与程序实现结果一致,如下图所示:
以上代码段的完整code见:GitHub/OpenSSL_Test
GitHub:https://github.com/fengbingchun/OpenSSL_Test
相关文章:

iOS UIImageView 加载含有汉字的url处理方法
NSString *url [model.pic stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; [self.headImgView sd_setImageWithURL:[NSURL URLWithString:url]];

《评人工智能如何走向新阶段》后记
由AI科技大本营下载自视觉中国自《评人工智能如何走向新阶段》一文发表(在内部)后,引来了中外专家、草根们的广泛议论,有深有浅,其中似有一些思考价值,故录入本文后记: 中外专家、草根们23条议…
用XCA(X Certificate and key management)可视化程序管理SSL 证书(3)--创建自己定义的凭证管理中心(Certificate Authority)...
在第“用XCA(X Certificate and key management)可视化程序管理SSL 证书(2)---创建证书请求”章节中,我们介绍了怎样用XCA创建SSL证书请求(Certificate Request),在一章节中…

C和C++安全编码笔记:并发
并发是一种系统属性,它是指系统中几个计算同时执行,并可能彼此交互。一个并发程序通常使用顺序线程和(或)进程的一些组合来执行计算,其中每个线程和进程执行可以在逻辑上并行执行的计算。这些进程和(或)线程可以在单处理器系统上使用分时抢占…

《评人工智能如何走向新阶段》后记(再续1)
由AI科技大本营下载自视觉中国中外专家、草根对《评人工智能如何走向新阶段》一文进行广泛议论,已在《后记》中发表原创(未加修改)的23条议论,现再续发24-30条如下: 24.最近半年来,人工智能的发展重心逐渐…

iOS UITextView 随键盘弹出界面上移
- (void)textViewDidBeginEditing:(UITextView *)textView { CGRect frame textView.frame; int offSet frame.origin.y 70 - (self.view.frame.size.height - 216.0); //iphone键盘高度为216.iped键盘高度为352 [UIView beginAnimations:"ResizeForKeyboard" co…

H3C 交换机命名规则
例:H3C-S5500-28C-EIH3C:为固定值,就是“H3C”这个品牌S的位置:代表产品系列『S 代表交换机SR 代表业务路由器』第一个5的位置:代表产品子系列号『3系为千兆上行,百兆下行的合适交换机 例:S3600 S31005系为全千兆的盒式交换机 …

iOS 时间选择器封装(含三种模式)
#import <UIKit/UIKit.h> typedef enum : NSUInteger { DatePickerViewDateTimeMode,//年月日,时分 DatePickerViewDateMode,//年月日 DatePickerViewTimeMode//时分 } DatePickerViewMode; protocol DateTimePickerViewDelegate <NSObject> optional /** * 确定按…

C和C++安全编码笔记:总结
《C和C安全编码》(原书第2版)这本书是2013年出版的。 这里是基于之前所有笔记的简单总结,笔记列表如下: 字符串:https://blog.csdn.net/fengbingchun/article/details/105325508 指针诡计:https://blog.csdn.net/fengbingchun/…

《评人工智能如何走向新阶段》后记(再续2)
由AI科技大本营下载自视觉中国从朋友那里获知,有一块供大家自由议论人工智能的园地(内部的),我通过有关关系进入后,一览之余,果然生动活泼,没有学究气,从已发表的30条议论来看。有原…

Dokku和Docker的完美配合
看到一篇不错的文章,收藏一下: 【编者的话】本文作者介绍了如何在单机上将Dokku和Docker结合。Dokku是一个小型的PaaS平台,只需使用Git将代码push到对应的仓库上就能自动触发部署,构建过程非常简单。但是Dokku对于用户来说&#x…

iOS封装分页效果
#import <UIKit/UIKit.h> interface WPageTitleView : UIView property (nonatomic,assign) NSInteger selectedIndex; //添加参数数组 property (nonatomic,strong) NSArray *titles; property (nonatomic,copy) void (^buttonSelected)(NSInteger index); end #impo…

Windows/Linux TCP Socket网络编程简介及测试代码
典型的网络应用是由一对程序(即客户程序和服务器程序)组成的,它们位于两个不同的端系统中。当运行这两个程序时,创建了一个客户进程和一个服务器进程,同时它们通过从套接字(socket)读出和写入数据在彼此之间进行通信。开发者创建一个网络应用…

《评人工智能如何走向新阶段》后记(再续3)
由AI科技大本营下载自视觉中国35.阿里巴巴旗下芯片公司平头哥在乌镇互联网大会上宣布开源低功耗微控制芯片(MCU)设计平台,这一平台面向 AIoT 时代的定制化芯片设计需求,目标群体包括芯片设计公司、IP 供应商、高校及科研院所等&am…

ffmpeg 基本用法大全
FFmpegFFmpeg 基本用法本课要解决的问题1.FFmpeg的转码流程是什么?2.常见的视频格式包含哪些内容吗?3.如何把这些内容从视频文件中抽取出来?4.如何从一种格式转换为另一种格式?5.如何放大和缩小视频?6.如何旋转&#x…

快过年了,为过完年跳槽的人准备一份面试题
设计模式是什么? 你知道哪些设计模式,并简要叙述? 设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型的事情。 1). MVC模式:Model View Control,把模型 视图 控制器 层进行解耦合编写。 2). MV…

Ubuntu上Vim安装NERDTree插件操作步骤
NERDTree是Vim的文件系统浏览器,使用此插件,用户可以直观地浏览复杂的目录层次结构,快速打开文件以进行读取或编辑,以及执行基本的文件系统操作。NERDTree源码在https://github.com/preservim/nerdtree。 这里通过Vundle安装NERD…

《评人工智能如何走向新阶段》后记(再续4)
由AI科技大本营下载自视觉中国41. 在人工智能感知阶段,依靠数据驱动的深度学习算法。目前5种最流行的深度学习架构: ① 递归神经网络(RNN)② 长短期记忆 (LSTM)/门控递归单元(GRU)③卷积神经网络…

电视游戏会是未来客厅娱乐的主角吗?
在时下流行的多屏生态概念中,电视虽为最大屏幕,但与智能手机、平板等小屏相比,属于相对较弱的一环。无移动性、自身交互性不足,在一定程度上影响着它在移动时代的发展。而作为最能体现其“吸睛能力”的——大屏娱乐功能࿰…

王爽著的《汇编语言》第3版笔记
王爽著的《汇编语言》(第3版)于2013年出版,虽然是2013年出版的,但书中部分内容感觉已过时: (1). 基于intel 8086 CPU介绍,intel 8086是英特尔公司上个世纪生产的芯片,是16位的,早已停产; (2).…

iOS 倒计时方法
//启动计时器 double delayInSeconds 10.0; dispatch_time_t popTime dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ //执行事件 NSLog("计时器结束了"); UIAlertController …

《评人工智能如何走向新阶段》后记(再续5)
由AI科技大本营下载自视觉中国51.今年发表的由俄罗斯“脑机接口”公司(Neurobotics)和莫斯科物理技术学院(MIPT)研究的一种全新“脑机接口”算法。利用“脑机接口”将人脑(EEG)神经元与脑外深度学习网络连接…

不说12306你会Die啊?当然不会,但会憋死
别嫌这标题话粗啊,只是突然想起了某小品中的一句台词儿而已。又是一年春运时,几十亿人口开始了兴奋着、痛苦着的大迁徙。12306开通有几年了吧,我今年才第一次用。因为父母要回老家,不想排队那么辛苦,所以才尝试一把网络…

汇编程序设计与计算机体系结构软件工程师教程笔记:处理器、寄存器简介
《汇编程序设计与计算机体系结构: 软件工程师教程》这本书是由Brain R.Hall和Kevin J.Slonka著,由爱飞翔译。中文版是2019年出版的。个人感觉这本书真不错,书中介绍了三种汇编器GAS、NASM、MASM异同,全部示例代码都放在了GitHub上,…
iOS 发布APP关于IDFA的相关内容
您的 App 正在使用广告标识符 (IDFA)。您必须先提供关于 IDFA 的使用信息或将其从 App 中移除,然后再上传您的二进制文件。 如果出现下边这两张图,你就会感到蛋蛋的忧伤 还有这个 怎么解决? 1,查看你所集成的SDK,看看…

《评人工智能如何走向新阶段》后记(再续6)
由AI科技大本营下载自视觉中国61. 在2019深度学习开发者峰会上,百度发布基于飞桨的图学习框架(PaddleGraphLearning,PGL)。近年来深度神经网络推动了人工智能的发展,但在实际场景中有大量数据是在非欧式空间的…

Android APP测试的日志文件抓取
1 log文件分类简介 实时打印的主要有:logcat main,logcat radio,logcat events,tcpdump,还有高通平台的还会有QXDM日志 状态信息的有:adb shell cat /proc/kmsg ,adb shell dmesg,…

汇编程序设计与计算机体系结构软件工程师教程笔记:指令
《汇编程序设计与计算机体系结构: 软件工程师教程》这本书是由Brain R.Hall和Kevin J.Slonka著,由爱飞翔译。中文版是2019年出版的。个人感觉这本书真不错,书中介绍了三种汇编器GAS、NASM、MASM异同,全部示例代码都放在了GitHub上,…

IOS视频编辑功能详解上篇-添加水印
前言 用代码在简单视频编辑中,主要就是加美颜、水印(贴图)、视频截取、视频拼接、音视频的处理,在美颜中,使用GPUImage即可实现多种滤镜、磨皮美颜的功能,并且可以脸部识别实时美颜等功能,这个…

《评人工智能如何走向新阶段》后记(再续7)
由AI科技大本营下载自视觉中国66. 谷歌近来研发用于基因科学的人工智能AlphaFold,根据基因序列预测生命基本分子一蛋白质的三维结构(AlphaFold与下国际围棋的AlphaGo似孪生兄弟),这是用来预测蛋白质折叠结构的能力或设计新的蛋白质…