基本概念
JWT(JSON Web Token)是一种基于 JSON 的开放标准(RFC 7519),用于在各方之间安全地传输信息。它是一种无状态的认证机制,通过数字签名确保信息的完整性和真实性。
JWT 的作用
- 无状态认证
无需服务器存储会话:JWT 包含所有必要的用户信息,服务器不需要在数据库或内存中存储会话状态
水平扩展:便于服务器集群的水平扩展,因为任何服务器都可以验证 JWT
减少数据库查询:验证用户身份时不需要查询数据库,提高性能 - 跨服务认证
微服务架构:在微服务环境中,JWT 可以在不同服务之间传递用户身份信息
跨域认证:支持跨域请求的身份验证,适用于前后端分离架构 - 信息交换
安全传输数据:通过数字签名确保数据在传输过程中不被篡改
包含自定义声明:可以在 Payload 中添加自定义信息,如用户角色、权限等
JWT 的结构
JWT 由三部分组成,用点(.)分隔:
1 | Header.Payload.Signature |
- Header(头部)
包含两部分信息:
令牌类型:通常为 “JWT”
签名算法:如 HMAC SHA256 或 RSA
示例:
1 | { |
- Payload(载荷)
包含声明(claims),分为三种类型:
注册声明:预定义的声明,如 iss(签发者)、exp(过期时间)、sub(主题)等
公共声明:可以自定义的声明,但建议使用 IANA JSON Web Token Registry 中定义的
私有声明:应用特定的声明,如用户 ID、角色等
示例:
1 | { |
- Signature(签名)
使用指定的算法对 Header 和 Payload 进行签名,确保消息未被篡改:
HMAC SHA256 算法:
1
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
RSA 算法:使用私钥签名,公钥验证
JWT 的使用流程
生成 JWT(登录时)
用户提供用户名和密码
服务器验证凭据
服务器生成 JWT,包含用户信息和过期时间
服务器将 JWT 返回给客户端
客户端存储 JWT(通常在 localStorage 或 cookie 中)使用 JWT(访问受保护资源时)
客户端在请求头中携带 JWT:Authorization: Bearer
服务器验证 JWT 的签名和过期时间
服务器从 JWT 中提取用户信息
服务器根据用户信息授权访问验证 JWT
检查签名是否有效
检查令牌是否过期
检查其他声明(如签发者、受众等)
Go 语言中的 JWT 实现
以 internal/utils/jwt.go 文件为例,通常包含以下功能:
- 生成 Token
1 | func GenerateToken(userID uint, username string) (string, error) { |
- 解析与验证 Token
1 | func ParseToken(tokenString string) (jwt.MapClaims, error) { |
- 在中间件中使用
1 | func JWTAuthMiddleware() gin.HandlerFunc { |
JWT 的优缺点
优点
无状态:服务器不需要存储会话信息,易于水平扩展
跨服务:适用于微服务架构和跨域场景
自包含:令牌包含所有必要信息,减少数据库查询
标准化:遵循 RFC 7519 标准,被广泛支持
缺点
- 令牌大小:包含较多信息时,令牌可能较大,增加网络传输开销
- 无法撤销:一旦签发,在过期前无法主动撤销(除非使用黑名单机制)
- 敏感信息:Payload 是 Base64 编码的,不是加密的,不应存储敏感信息
- 签名密钥管理:需要安全管理签名密钥,防止泄露
最佳实践
- 使用安全的签名算法:优先使用 RS256(非对称加密)而非 HS256(对称加密)
- 设置合理的过期时间:根据应用场景设置适当的过期时间
- 存储敏感信息:不在 Payload 中存储敏感信息,如密码
- 使用 HTTPS:在传输过程中使用 HTTPS 保护 JWT
- 实现令牌刷新机制:提供刷新令牌的接口,避免用户频繁登录
- 添加黑名单:用于撤销已签发但未过期的令牌
输入输出示例
生成 Token:
1 | token, err := GenerateToken(1, "alice") |
输出:
1 | Generated token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFsaWNlIiwiZXhwIjoxNzE0MTc3MjAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c |
解析 Token:
1 | claims, err := ParseToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFsaWNlIiwiZXhwIjoxNzE0MTc3MjAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c") |
输出:
1 | plainText |
总结
JWT 是一种强大的认证机制,通过无状态设计和数字签名,为现代应用提供了安全、高效的身份验证方案。它特别适用于前后端分离架构、微服务系统和跨域场景,能够简化认证流程并提高系统的可扩展性。
在使用 JWT 时,需要注意安全最佳实践,如使用安全的签名算法、合理设置过期时间、保护签名密钥等,以确保系统的安全性。通过正确实现和使用 JWT,可以构建更加安全、可靠的认证系统。
说些什么吧!