引言:为什么在 Go 中需要 OAuth 2.0 和 JWT?
\n现代 Web 应用程序和 API 很少能绕过授权系统。如果您正在使用 Go (Golang) 进行开发,并希望保护您的端点,您需要了解两项关键技术:OAuth 2.0(访问委托协议)和 JWT(JSON Web Token——一种紧凑的令牌格式)。
\n在本文中,我们将从零开始讲解如何在 Go 中实现安全授权。您将了解到:
\n- \n
- OAuth 2.0 与 JWT 的区别以及它们如何协同工作。 \n
- 如何在 Go 中生成和验证 JWT 令牌。 \n
- 如何构建一个最小的 OAuth 2.0 授权(客户端凭证流程)。 \n
- 如何使用中间件保护 REST API。 \n
本文面向已经熟悉 Go 基础和 HTTP 服务器的初级开发者。
\n\n基础知识:OAuth 2.0 和 JWT 不是一回事
\n许多初学者会混淆这两个概念。让我们先明确一下。
\n\n什么是 OAuth 2.0?
\nOAuth 2.0 是一种授权协议,它允许一个服务(客户端)代表用户获得对另一个服务(服务器)资源的有限访问权限。想象一下,您想通过 Google 登录一个网站。该网站不会获取您的密码——它会从 Google 获得一个临时令牌,该令牌仅允许访问您的电子邮件(并且需要您的同意)。
\nOAuth 2.0 中的主要角色:
\n- \n
- 资源所有者 — 数据的所有者(通常是用户)。 \n
- 客户端 — 想要获得访问权限的应用程序。 \n
- 授权服务器 — 验证后颁发令牌的服务器。 \n
- 资源服务器 — 存储受保护数据并验证令牌的服务器。 \n
什么是 JWT?
\nJWT (JSON Web Token) 是令牌本身的格式。它是由点分隔的三部分组成的字符串:header.payload.signature。JWT 可以包含任何数据(例如,用户 ID、角色、过期时间),并使用密钥签名,以防止被篡改。
OAuth 2.0 不绑定 JWT——令牌可以是任何字符串。然而,在实践中,JWT 最常用,因为它是自包含的:服务器无需在数据库中存储会话,所有信息都可以即时验证。
\n\n在 Go 中实现 JWT:令牌的生成与验证
\n我们从实践开始。要在 Go 中使用 JWT,我们将使用 golang-jwt/jwt/v5 库。安装它:
go get github.com/golang-jwt/jwt/v5\n\n生成访问令牌
\n创建一个函数,该函数接收用户 ID 并返回一个签名的 JWT 令牌,有效期为 1 小时。
\npackage main\n\nimport (\n "time"\n "github.com/golang-jwt/jwt/v5"\n)\n\nvar jwtSecret = []byte("your-secret-key") // 在生产环境中,请存储在 .env 文件中!\n\ntype Claims struct {\n UserID uint `json:"user_id"`\n jwt.RegisteredClaims\n}\n\nfunc GenerateAccessToken(userID uint) (string, error) {\n claims := Claims{\n UserID: userID,\n RegisteredClaims: jwt.RegisteredClaims{\n ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour)),\n IssuedAt: jwt.NewNumericDate(time.Now()),\n Issuer: "my-app",\n },\n }\n token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)\n return token.SignedString(jwtSecret)\n}\n\n验证和解析 JWT
\n现在,编写一个中间件,用于验证来自 Authorization: Bearer <token> 头的令牌。
func ValidateToken(tokenString string) (*Claims, error) {\n token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {\n // 检查是否使用了正确的签名方法\n