一文了解JWT Token

181 阅读4分钟

提示:本文摘自「云原生AI实战营」中的「Go项目开发中级实战课」体系课。

在实际开发中,使用令牌认证,还有其他很多好处。掌握令牌认证的原理和实现方法,是 Go 语言开发者,必备的核心技能之一。

由于 miniblog 使用 JWT Token 进行身份认证,为了降低学习难度并为后续代码实现奠定基础,本节课将介绍 JWT 的核心内容。

JWT 认证流程

学习 JWT 的最佳方式是通过其认证流程理解其原理。认证流程如下图所示。

上图展示了 JWT 的认证流程,具体流程如下:

  1. 客户端(通常是前端)通过用户名和密码进行登录;
  2. 服务端收到请求后会验证用户名和密码,若与数据库记录不一致,则认证失败,若一致,则认证通过。认证通过后,服务端会签发一个具有有效期的 Token 并返回给客户端;
  3. 客户端接收到 Token 后会将其缓存,例如存储在浏览器的 Cookie 或本地存储中,方便下次调用时使用;
  4. 客户端在之后的每次 API 请求中携带缓存的 Token;
  5. 服务端接收到请求后会验证请求中携带的 Token,验证通过后继续处理业务逻辑并返回数据;
  6. 如果 Token 快过期,前端会调用 Token 刷新接口续期 Token,避免用户再次登录。之后,会使用续期后的 Token 发送 API 请求。

提示: Go 项目开发中,Token 有效期通常设置为 2 小时。

JWT Token 格式

在 JWT 中,Token 由 Header、Payload、Signature 三部分组成,中间用英文点号(.)隔开,并使用 Base64 编码。JWT Token 示例如下:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzkwNzgwMDUsImlhdCI6MTczNTQ3ODAwNSwibmJmIjoxNzM1NDc4MDA1LCJ4LXVzZXItaWQiOiJ1c2VyLXc2aXJrZyJ9.GromRG7kK90UfU_Q5iOSHs_xE-zSk0e0HLHqJQUjYMU

(1)Header 介绍

JWT Token 的 Header 中包含两部分信息:Token 的类型和 Token 所使用的加密算法。JWT Header 示例如下:

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

上述示例表明,Token 类型是 JWT,加密算法为 HS256alg 支持多种加密算法)。

(2)Payload 载荷介绍

Payload 中携带了 Token 的具体内容,其中包含一些标准字段,当然也可以添加额外字段以表达更丰富的信息。这些信息可以用于更复杂的处理场景,例如记录请求的用户 ID、用户名等。标准字段包括:

  • iss:JWT Token 的签发者;
  • sub:主题;
  • exp:JWT Token 的过期时间;
  • aud:接收 JWT Token 的一方;
  • iat:JWT Token 的签发时间;
  • nbf:JWT Token 的生效时间;
  • jti:JWT Token 的唯一标识(ID)。

Payload 示例如下所示:

{
  "id": 2,
  "userID": "user-p7q78j",
  "nbf": 1527931805,
  "iat": 1527931805
}

(3)Signature 签名介绍

Signature 是 Token 的签名部分,其生成方式如下:

  • 使用 Base64 对 header.payload 进行编码;
  • 使用密钥(Secret)对编码后的内容进行加密,加密后的内容即为 Signature。

密钥相当于一个密码,存储在服务端,通常通过配置文件设置密钥的值。

最终生成的 Token 如下所示:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzkwNzgwMDUsImlhdCI6MTczNTQ3ODAwNSwibmJmIjoxNzM1NDc4MDA1LCJ4LXVzZXItaWQiOiJ1c2VyLXc2aXJrZyJ9.GromRG7kK90UfU_Q5iOSHs_xE-zSk0e0HLHqJQUjYMU

签名后,服务端会返回生成的 Token。客户端在下次请求时会携带该 Token,服务端收到 Token 后会解析出 header.payload,然后使用相同的加密算法和密码对 header.payload 再次加密,并将加密后的 Token 与收到的 Token 进行比对。如果二者相同,则验证通过;如果不相同,则返回 HTTP 401 Unauthorized 错误。

JWT Token 生成示例

下述代码展示了具体如何生成一个 JWT Token,通过代码可以详细的了解 Token 生成的方式:

#!/bin/bash

# 定义Header
HEADER='{"alg":"HS256","typ":"JWT"}'

# 定义Payload
PAYLOAD='{"exp":1739078005,"iat":1735478005,"nbf":1735478005,"x-user-id":"user-w6irkg"}'

# 定义Secret(用于签名)
SECRET="Rtg8BPKNEf2mB4mgvKONGPZZQSaJWNLijxR42qRgq0iBb5"

# 1. Base64编码Header
HEADER_BASE64=$(echo -n "${HEADER}" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n')

# 2. Base64编码Payload
PAYLOAD_BASE64=$(echo -n "${PAYLOAD}" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n')

# 3. 拼接Header和Payload为签名数据
SIGNING_INPUT="${HEADER_BASE64}.${PAYLOAD_BASE64}"

# 4. 使用HMAC SHA256算法生成签名
SIGNATURE=$(echo -n "${SIGNING_INPUT}" | openssl dgst -sha256 -hmac "${SECRET}" -binary | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n')

# 5. 拼接最终的JWT Token
JWT="${SIGNING_INPUT}.${SIGNATURE}"

# 输出JWT Token
echo "Generated JWT Token:"
echo "${JWT}"

miniblog 实现 HTTPS 通信

如果你想学习真实项目中,如何设计和实现 HTTPS 通信,可阅读 github.com/onexstack/m… 源码。

  • 知识星球:云原生AI实战营。10+ 高质量体系课( Go、云原生、AI Infra)、15+ 实战项目,P8 技术专家助你提高技术天花板,入大厂拿高薪;
  • 公众号:令飞编程,分享 Go、云原生、AI Infra 相关技术。回复「资料」免费下载 Go、云原生、AI 等学习资料;
  • 哔哩哔哩:令飞编程 ,分享技术、职场、面经等,并有免费直播课「云原生AI高新就业课」,大厂级项目实战到大厂面试通关;