Go语言中的OAuth 2.0和JWT入门
现代Web应用程序和API需要可靠且安全的身份验证和授权系统。该领域最流行的两个标准是OAuth 2.0和JWT(JSON Web Tokens)。在Go语言(Golang)中,由于内置的并发支持、高性能和丰富的库生态系统,实现这些机制变得特别高效。
在本文中,我们将详细讲解如何在Go中实现OAuth 2.0和JWT授权。您将学习如何配置服务器、生成和验证令牌,以及保护您的端点。本文内容对初学者和经验丰富的Go开发人员都很有帮助。
OAuth 2.0和JWT基础
什么是OAuth 2.0?
OAuth 2.0是一种授权协议,允许应用程序在不传递密码的情况下获得对用户资源的有限访问权限。取而代之的是使用访问令牌(access tokens)。该过程的主要参与者包括:
- Resource Owner — 拥有数据的用户
- Client — 请求访问的应用程序
- Authorization Server — 颁发令牌的服务器
- Resource Server — 提供受保护资源的服务器
什么是JWT?
JWT(JSON Web Token)是一种紧凑且自包含的格式,用于以JSON对象的形式在各方之间传输数据。令牌由三部分组成,用点分隔:
header.payload.signatureJWT的优点:
- 无需在服务器上存储会话(无状态)
- 包含所有必要信息(claims)
- 经过签名以验证完整性
在Go中实现JWT授权
为了在Go中使用JWT,我们将使用流行的库golang-jwt/jwt/v5。使用以下命令安装它:
go get github.com/golang-jwt/jwt/v5生成JWT令牌
创建一个函数来生成access和refresh令牌:
package auth
import ( "time" "github.com/golang-jwt/jwt/v5")
var jwtSecret = []byte("your-secret-key")
type Claims struct { UserID uint `json:"user_id"` Email string `json:"email"` jwt.RegisteredClaims}
func GenerateAccessToken(userID uint, email string) (string, error) { claims := &Claims{ UserID: userID, Email: email, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(15 * time.Minute)), IssuedAt: jwt.NewNumericDate(time.Now()), Issuer: "myapp", }, }
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(jwtSecret)}
func GenerateRefreshToken(userID uint) (string, error) { claims := &Claims{ UserID: userID, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(7 * 24 * time.Hour)), IssuedAt: jwt.NewNumericDate(time.Now()), }, }
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(jwtSecret)}验证JWT令牌
用于在HTTP请求中验证令牌的中间件:
package middleware
import ( "net/http" "strings" "github.com/gin-gonic/gin" "myapp/auth")
func AuthMiddleware() gin.HandlerFunc { return func(c *gin.Context) { authHeader := c.GetHeader("Authorization") if authHeader == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "missing authorization header"}) c.Abort() return }
tokenString := strings.TrimPrefix(authHeader, "Bearer ") if tokenString == authHeader {