- 开发工具
【免费下载链接】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.
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
解析结果为一个字典,固定包含三个顶层键:
| 键 | 类型 | 说明 |
|---|---|---|
header | object | JWT 头部解码后的 JSON 对象,典型键为alg(string,算法,如HS256)与typ(string,类型,通常为JWT);实际包含哪些键取决于令牌头部本身 |
payload | object | JWT 载荷(claims)解码后的 JSON 对象,<key name>的值可以是 string/integer/float/boolean/null |
signature | string | 签名段的字节序列,转为冒号分隔的十六进制表示,如49:f9:4a:... |
完整示例
测试用例中使用的是一条真实的三段式 HS256 JWT(来自 tests/test_jwt.py):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cjc.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):
- 平台兼容性检查:调用
jc.utils.compatibility(__name__, info.compatible, quiet),仅在当前平台属于兼容列表(linux、darwin、cygwin、win32、aix、freebsd)时继续; - 输入类型检查:
jc.utils.input_type_check(data)确认输入为字符串; - 空数据判定:
jc.utils.has_data(data)为假时直接返回{},这是测试用例test_jwt_nodata所验证的行为(tests/test_jwt.py); - 三段分割:
header, payload, signature = data.split('.')。这里要求输入恰好由两个.分隔成三段,否则 Python 的解包会抛出ValueError——从源码结构看,传入非 JWT 格式的数据会以异常形式暴露,而不是返回部分结果; - 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_seperatedbinascii.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.
相关推荐
用 jemalloc mallctl 看进程内存的真相
用 jemalloc mallctl 看进程内存的真相 上次 OOM 复盘时,heap profile 一片干净,RSS 却在六小时内从 4GB 爬到 9GB,
内存管理amlogic-s9xxx-armbian 移植:S905X3 电视盒变 2 瓦 Linux 服务器
amlogic s9xxx armbian 移植:S905X3 电视盒变 2 瓦 Linux 服务器 这台 S905X3 盒子已连续运行两个多月,Docker、
嵌入式开发工具构建工具操作系统如何快速掌握tymon/jwt-auth:深入解析JWT令牌三部分结构与生成机制
如何快速掌握tymon/jwt auth:深入解析JWT令牌三部分结构与生成机制 tymon/jwt auth是一款为Laravel和Lumen框架设计的JSO
认证鉴权后端安全
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考