【最后203篇系列】039 JWT使用

简单先过一下概念

JWT(JSON Web Token)一般用来身份校验和授权。由三部分组成:Header.Payload.Signature,其中Header是加密算法和令牌类型;Payload是核心负载,包括了用户身份和权限信息,Signature则是校验。

JWT必须和HTTPS配合使用才能保证安全,否则容易被中间人攻击。

整体使用流程如下:

  1. 用户登录 → 服务器验证凭证
  2. 服务器生成JWT → 返回给客户端
  3. 客户端存储JWT → 通常在localStorage或cookie中
  4. 客户端发送请求 → 在Authorization头中包含JWT
  5. 服务器验证JWT → 返回请求的数据

为啥我要搞JWT?

一方面是历史的原因。以前做了很多后端服务,主要是内部在使用,图省事也没有搞。后来发现,用的人多了以后多少是有点失控的。不清楚谁在用,用了多少。

然后我的微服务越来越多,而且也开始做前端。如果说后端很多服务还是比较个性化的,如果参数不对甚至调不通,那么到了前端就不同了:很多应用一目了然。所以就要开始做授权和鉴权。当然这里仍然可以偷点懒,比如服务起在本地,或者IP白名单什么的。

最近,我觉得智能网关是非常重要的一环。网关需要处理每一个请求,把请求体解开通常是不行的,网关的开销过大,很多应用就没有意义了。所以网关能利用的请求信息最好是放在请求头,而既然要放请求头,而且要通用,那么JWT就是一个很好的选择。

  • 1 JWT 是一个通行的规范
  • 2 JWT 里带了鉴权、也可以设置权限范围
  • 3 JWT 里可以自定义一些其他内容,正好用于区分不同的路由

所以现在必须要把JWT工程化了。

JWT payload设计

尽量使用通用的字段,然后稍微对其中一些字段重定义

字段 中文 作用
iss 签发者 识别 token 来源,安全边界
aud 受众 识别 token 面向哪个系统
sub 主体 用户或客户端标识,业务身份
jti token 唯一 ID 日志追溯、重放防护、撤销控制
scope 权限范围 接口权限控制
iat 签发时间 token 生命周期参考
exp 过期时间 token 生命周期控制
  • iss和aud会被重定义为该jwt可用的微服务,逻辑上对应 tier1和tier2,这种两级命名足够覆盖我的微服务体系
  • sub: 则作为用户的身份标志,比如user_id
  • jti: 用于日志分析和特定控制(可以用布隆过滤器来实现黑名单控制)
  • scope: 用户在某个子系统(微服务)下允许的权限
  • iat和exp: 基本的声明周期控制

这样一套JWT可实现每次处理时,系统知道用户是谁,现在计划访问什么系统,可以具有怎样的权限

未来,For 智能网关:

智能网关收到一个请求,通过解析header中的jwt,就可以:

  • 1 知道用户sub向 iss.aud.url 发起请求
  • 2 网关可以获取 iss.aud.url的权限要求(redis kv), 和scope比较(is in),这样就可以决定是否要转发

智能网关的智能性主要体现在路由的策略上:

  • 记忆性:每个请求存在记忆性,当某个pid(时空唯一)被反复请求时,智能网关会根据被转发的服务来决定如何应答。
  • 策略性:一个请求到了以后,有若干下游服务可以提供同质(同版本的扩展)和异质(不同版本),智能网关会进行全量或者部分的多发,来评估性能或者分摊压力。

用户注册表

需要使用一个数据库来产生初始的jwt颁发。

基于mysql数据建表

表名:jwt_users

  • id - 自增主键
  • pid - 主键
  • username - 不可改,不可重的字段,不超过100字符
  • email - 不可空
  • phone - 可空,非缺失时按大陆手机号格式
  • password - 加密存储 bcrypt
  • is_enable - 是否启用
  • create_time - 创建时间
  • update_time - 修改时间

生成字段:

password 由 username + 创建时间生成

pid是依据用户名+创建时间的md5值

用户权限表

存储用户可使用的权限

表名: jwt_auth

  • jwt_user_pid : jwt_users 的pid,索引
  • tier1: 微服务一级名称,不超过200字符,索引
  • tier2: 微服务二级名称, 不超过200字符,索引
  • scope: 权限内容,TEXT格式; * 开头代表完全许可; ~代表禁止功能列表;否则代表许可功能列表;每个功能许可将以api.read这样的格式声明
  • is_enable - 是否启用
  • create_time - 创建时间
  • update_time - 修改时间

JWT相关设置及函数

各个服务器上采用相同的JWT_KEY和JWT_ALGO才能复现signature,从而确保不被伪造

JWT_KEY和JWT_ALGO直接写入env文件中。

  • create_jwt_token: 用户输入iss,aud(对应着微服务的一级和二级),和对应的scope(默认为 * ,后续可以进一步细化)
  • verify_jwt_token: 验证jwt,成功时返回payload,失败时则为False

创建jwt模块,并实现以上两个函数,

创建数据模型(内存) -- node

jwt_user

  • username
  • email
  • password
  • phone 可选

参考 data.JwtUsers 创建

jwt_auth

  • tier1
  • tier2
  • scope

参考 data.JwtAuth创建

jwt_payload

  • iss 对应 tier1
  • aud 对应 tier2
  • sub 主体,对应用户的 pid
  • scope 默认 *
  • duration 默认 60(分钟)

参考 data.JwtAuthjwt_token.create_jwt_token

  • 1 从内存节点到硬盘节点jwt_user_to_jwt_users
  • 2 从内存节点到硬盘节点 jwt_user_auth_to_jwt_auth

创建子图 -- subgraph

  • 1 用户创建引导:创建一个交互式命令行,引导用户完成;基于link.jwt_user_to_jwt_users
  • 2 权限创建引导:创建一个交互式命令行,引导用户完成,基于link.jwt_user_auth_to_jwt_auth
  • 3 token创建:创建一个交互式命令行,引导用户完成。首先提示进行用户名和密码的认证,然后引导用户输入node.memory_node.jwt_payload对应的字段,校验对应字段在data.JwtAuth中被允许,最后通过jwt_token.create_jwt_token返回一个jwt。为这个子图(CreateTokenGraph)创建多一个示例,在生成了jwt之后验证jwt(使用jwt_token.verify_jwt_token).

实现

用opencode + minimax2.1 构造

先创建项目,然后创建分支 v0.1

  • 1 基于st-0008 创建项目文件结构(st系列我在之前文章提过,是总结下来的固定做法)
  • 2 基于st-0003 创建jwt_users 的ORM。
  • 3 生成一个username: test, email: test@test.com, password:test的用户
  • 4 为test创建test_ms.test_api.* 权限
  • 5 基于st-0007 创建 JWT相关函数
  • 6 基于st-0001 参考data.JwtUsers,创建 jwt user 相关模型
  • 7 基于st-0002 建一个link函数,from node.memory_node.jwtUser to data.JwtUsers
  • 8 基于st-0009,完成用户创建引导:创建一个交互式命令行,引导用户完成;基于link.jwt_user_to_jwt_users,但是要先判断用户是否可以创建(比如已存在或者其他限制)
  • 9 基于st-0001 参考data.JwtAuth,创建 jwt auth 相关模型
  • 10 基于st-0002 建一个link函数, from node.memory_node.jwtUserAuth to data.JwtAuth
  • 11 基于st-0009,创建一个交互式命令行,完成用户创建引导,基于link.jwt_user_auth_to_jwt_auth ,同样需要判断是否已经存在,采用 create or update 的方式完成权限设置。
  • 12 基于st-0001,参考 data.JwtAuthjwt_token.create_jwt_token 创建jwt_payload原型
  • 13 创建fronend 文件夹,在其下使用gradio创建前端,将三个子图流程使用前端实现。

使用

使用三个子图进行用户创建、用户权限创建、token生成, 所以我在其他服务中,只要有了.env中的环境变量和 verify_jwt_token 这个函数就可以验证token了

有一个前端是比较重要的,使用gradio可以比较简单的进行操作和检查

验证

最终开发形成的文件如下:

回顾

我要的具体功能实现了。整个过程耗时一天,具体我参与的时间只有4-5个小时,严格来说我改的代码只有3行(在最后搭建前端服务的时候没有给规范,大模型在载入env文件上竟然有个很傻的错误:没有载入env却先获取环境变量了,关键是不构成启动报错,但是--> 大模型的逻辑还是有点弱)。

其中我花的时间80%在思考、修改规范和等待。因为部分设计细节我之前是没想清楚的,以及我的规范之前写的还不够完善,所以是边交互、边开发、边完善的过程。这样的结果就是进一步强化抽象经验,使得整个过程足够规范(类似以前的写文档),这些规范最终也会被贯彻执行(因为大模型非常适合这么调教,而人往往不是这样的)。

这意味什么?

逻辑密度会进一步提升。比如我之前有设想给做好的后端服务带上一个前端,但是在一次开发(可以认为类似session)以前没有精力实现,现在就可以了。

另外,由于结构上高度清晰,未来要debug或者进一步加功能是非常简单的。逻辑越清晰,本身也会更加稳定。

时间可控性变强。 由于开发者需要的是把东西"想明白,说清楚",不在低层面的代码细节上浪费时间,或者至少说,对于确定性的数据处理逻辑(如ETL类)是完全可以交给大模型实现的。

我觉得大模型时代 ,变化将会更有趣。更抽象的思考,更结构化的表达!

相关推荐
独好紫罗兰2 小时前
对python的再认识-基于数据结构进行-a006-元组-拓展
开发语言·数据结构·python
Dfreedom.2 小时前
图像直方图完全解析:从原理到实战应用
图像处理·python·opencv·直方图·直方图均衡化
铉铉这波能秀2 小时前
LeetCode Hot100数据结构背景知识之集合(Set)Python2026新版
数据结构·python·算法·leetcode·哈希算法
怒放吧德德3 小时前
Python3基础:基础实战巩固,从“会用”到“活用”
后端·python
aiguangyuan3 小时前
基于BERT的中文命名实体识别实战解析
人工智能·python·nlp
喵手3 小时前
Python爬虫实战:知识挖掘机 - 知乎问答与专栏文章的深度分页采集系统(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·采集知乎问答与专栏文章·采集知乎数据·采集知乎数据存储sqlite
铉铉这波能秀3 小时前
LeetCode Hot100数据结构背景知识之元组(Tuple)Python2026新版
数据结构·python·算法·leetcode·元组·tuple
kali-Myon3 小时前
2025春秋杯网络安全联赛冬季赛-day2
python·安全·web安全·ai·php·pwn·ctf
Olamyh3 小时前
【 超越 ReAct:手搓 Plan-and-Execute (Planner) Agent】
python·ai