news 2026/9/25 3:43:10

jc JWT 解析器实战:把 JWT 令牌结构化为 JSON,及其解码实现的源码剖析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
jc JWT 解析器实战:把 JWT 令牌结构化为 JSON,及其解码实现的源码剖析
  • 开发工具

【免费下载链接】jc

CLI tool and python library that converts the output of popular command-line tools, file-types, and common strings to JSON, YAML, or Dictionaries. This allows piping of output to tools like jq and simplifying automation scripts.

项目地址:https://gitcode.com/gh_mirrors/jc/jc
点击查看免费下载

jc 提供jwt解析器(CLI 参数--jwt),用于将 JWT(JSON Web Token)字符串直接转换为结构化的 JSON,便于jq过滤和自动化脚本消费。阅读本文后,你将掌握该解析器的完整使用方式(CLI 与 Python 模块)、输出 Schema 的逐字段含义,以及从 base64url 解码、签名十六进制化到边界行为处理的源码级实现细节,能够在调试 API 令牌、审计载荷字段时快速上手并理解其行为边界。

文档明确声明:jc不会校验 JWT 的完整性(不验签)。该解析器仅做结构解码,任何安全验证(签名有效性、exp过期检查等)需要由调用方自行完成。

快速上手

CLI 用法

将 JWT 字符串通过管道传给jc --jwt:

$ echo "eyJhbGciOiJIUzI1N..." | jc --jwt

加上-p参数可获得 pretty-print 的 JSON 输出:

% echo 'eyJhbGciOiJIUzI1N...' | jc --jwt -p { "header": { "alg": "HS256", "typ": "JWT" }, "payload": { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }, "signature": "49:f9:4a:c7:04:49:48:c7:8a:28:5d:90:4f:87:f0:a4:c7..." }

--jwt是 README 解析器参数表中登记的标准参数之一(见 README.md)。

模块用法

在 Python 代码中,推荐使用 jc 的高层 APIjc.parse():

import jc result = jc.parse('jwt', jwt_string)

jc.parse()是统一分发入口:它通过get_parser()按模块名/CLI 名/参数名解析出对应解析模块后,调用其parse()方法(见 jc/lib.py)。因此jc.parse('jwt', ...)等价于直接导入解析模块:

import jc.parsers.jwt result = jc.parsers.jwt.parse(jwt_string)

输出 Schema

解析结果为一个字典,固定包含三个顶层键:

键类型说明
headerobjectJWT 头部解码后的 JSON 对象,典型键为alg(string,算法,如HS256)与typ(string,类型,通常为JWT);实际包含哪些键取决于令牌头部本身
payloadobjectJWT 载荷(claims)解码后的 JSON 对象,<key name>的值可以是 string/integer/float/boolean/null
signaturestring签名段的字节序列,转为冒号分隔的十六进制表示,如49:f9:4a:...

完整示例

测试用例中使用的是一条真实的三段式 HS256 JWT(来自 tests/test_jwt.py):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

jc.parsers.jwt.parse()的完整输出为(见 tests/test_jwt.py 的断言值):

{ "header": {"alg": "HS256", "typ": "JWT"}, "payload": {"sub": "1234567890", "name": "John Doe", "iat": 1516239022}, "signature": "49:f9:4a:c7:04:49:48:c7:8a:28:5d:90:4f:87:f0:a4:c7:89:7f:7e:8f:3a:4e:b2:25:5f:da:75:0b:2c:c3:97" }

可以看到签名段SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c被解码为 32 字节(HS256 输出 256 位),并以冒号分隔的十六进制呈现,每两个十六进制字符对应一个字节。

parse() API

解析入口函数签名(见 jc/parsers/jwt.py):

def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict

参数说明:

  • data(string):待解析的 JWT 字符串。解析器会先strip()去除首尾空白再分割,因此携带尾部换行的字符串(如从文件重定向读取的)可以直接传入;
  • raw(boolean):True时返回未经后处理的数据。对本解析器而言,后处理函数_process()是直接透传(见 jc/parsers/jwt.py),所以raw=True与raw=False的输出完全一致;
  • quiet(boolean):True时抑制警告信息;
  • 返回值为Dict:解析成功时为三段式结构体;输入为空时返回{}(空字典)。

源码实现剖析

整个解析逻辑集中在 jc/parsers/jwt.py,核心流程位于parse()内部(jc/parsers/jwt.py):

  1. 平台兼容性检查:调用jc.utils.compatibility(__name__, info.compatible, quiet),仅在当前平台属于兼容列表(linux、darwin、cygwin、win32、aix、freebsd)时继续;
  2. 输入类型检查:jc.utils.input_type_check(data)确认输入为字符串;
  3. 空数据判定:jc.utils.has_data(data)为假时直接返回{},这是测试用例test_jwt_nodata所验证的行为(tests/test_jwt.py);
  4. 三段分割:header, payload, signature = data.split('.')。这里要求输入恰好由两个.分隔成三段,否则 Python 的解包会抛出ValueError——从源码结构看,传入非 JWT 格式的数据会以异常形式暴露,而不是返回部分结果;
  5. base64url 解码:header 与 payload 使用urlsafe_b64decode(seg + '==')解码后以 UTF-8 转字符串,再经json.loads还原为字典;签名段只做字节解码,不做 UTF-8 转字符串。

为什么解码前要追加'=='

JWT 规范(RFC 7515)规定 base64url 编码省略末尾填充。Python 的urlsafe_b64decode对缺少填充的输入会报错,因此解析器对每段统一追加'=='(见 jc/parsers/jwt.py)。无论原段余数为 1 还是 2 个字符,'=='都提供足够的填充量;对已经是 4 的倍数或已带填充的段,Python 的 base64 解码器能够容忍多余的填充字符。这种写法使解析器同时兼容带填充与不带填充的输入。

签名的冒号十六进制化与 Python 版本兼容

签名段通过私有函数_b2a()(jc/parsers/jwt.py)转换为冒号分隔的十六进制字符串:

def _b2a(byte_string: bytes) -> str: """Convert a byte string to a colon-delimited hex ascii string""" try: return binascii.hexlify(byte_string, ':').decode('utf-8') except TypeError: hex_string = binascii.hexlify(byte_string).decode('utf-8') colon_seperated = ':'.join(hex_string[i:i+2] for i in range(0, len(hex_string), 2)) return colon_seperated

binascii.hexlify()的sep分隔符参数是 Python 3.8 才引入的;为了兼容 Python 3.6/3.7,代码在TypeError时回退为手动按字节切片再拼冒号。冒号分隔的写法让长签名在 JSON/日志中更易逐字节比对,也是该 Schema 中signature为 string 而非字节的直接原因。

关于"不验签"的再说明

文档与源码均表明:parse()只解包不验证。signature字段只是对第三段字节原样呈现,不会用header.alg或任何密钥去复核其正确性。因此该解析器适合检视令牌结构(查看 claims、确认头部算法、人工比对签名字节),而不适合做认证判定的唯一依据。

测试覆盖

tests/test_jwt.py 包含两个用例,共同界定了解析器的行为边界:

  • test_jwt_nodata:空字符串输入(quiet=True)应返回{};
  • test_jwt_example:完整三段 HS256 JWT 应精确命中上述 JSON 输出,包括 32 字节签名的逐字节十六进制值。

这两个断言值可以直接作为集成测试的期望基准。

解析器信息

  • 元数据(jc/parsers/jwt.py 的info类):version = '1.1',作者 Kelly Brazil(kellyjonbrazil@gmail.com),description = 'JWT string parser';
  • tags:['standard', 'string', 'slurpable']—— 标准(非流式)解析器,输入为字符串而非命令输出,且支持--slurp命令行选项(将多行/多段输入聚合后解析);
  • 兼容性:linux、darwin、cygwin、win32、aix、freebsd;
  • 源码位置:jc/parsers/jwt.py;
  • 配套文档:docs/parsers/jwt.md。

小结

jc --jwt以极小的实现体量覆盖了 JWT 检视的常见诉求:三段分割 → base64url 解码(自动补填充)→ JSON 还原 → 签名十六进制化,输出稳定的三键 Schema,可直接接jq进一步过滤(例如取payload.sub)。需要牢记的前提是:它不验签,也不做时间类 claims 的语义检查;在自动化流水线中,建议把它当作"结构化观察工具",与独立的签名验证逻辑配合使用。

  • 开发工具

【免费下载链接】jc

CLI tool and python library that converts the output of popular command-line tools, file-types, and common strings to JSON, YAML, or Dictionaries. This allows piping of output to tools like jq and simplifying automation scripts.

项目地址:https://gitcode.com/gh_mirrors/jc/jc
点击查看免费下载
上一篇:GRR服务器架构深度解析:如何构建高可用取证平台
下一篇:HS2游戏补丁安装与问题解决全攻略

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 3:40:49

AI Agent工程落地指南:从模型调用到结果交付

做了两年多AI Agent项目&#xff0c;带过团队也踩过无数坑&#xff0c;我最大的感受是&#xff1a;AI Agent工程师真正要解决的&#xff0c;不是"调用模型"&#xff0c;而是"交付结果"。这个区别几乎决定了一个Agent项目是停留在Demo阶段&#xff0c;还是能…

作者头像 李华
网站建设 2026/9/25 3:40:30

AI Agent版本控制:代码、Prompt、模型与评估集的四层方案

这段时间一直在做 AI Agent 的工程化实践&#xff0c;系列写到第四十五篇&#xff0c;我越来越感觉到一个反直觉的事实&#xff1a;Agent 项目最难维护的不是代码&#xff0c;而是"行为"本身。版本控制对 AI Agent 来说&#xff0c;管的绝不只是代码那部分。很多从传…

作者头像 李华
网站建设 2026/9/25 3:37:25

嵌入式量产烧录良率排查指南:从接触到电源的全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华