首先,让我们从一些背景信息开始。 JWT代表JSON Web令牌,它是将各方之间的信息安全传输为JSON对象的标准。 JWT通常用于身份验证和授权目的,它们由三个部分组成:标头,有效载荷和签名。
当用户登录到您的应用程序时,您可以生成JWT并将其发送回客户端。然后,客户端可以将JWT包括在对您的API的后续请求中,您的API可以使用JWT来验证用户并授权访问受保护的资源。
现在,让我们研究代码。首先,我们使用GIN框架创建基本的Golang API。确保在继续之前安装了杜松子酒:
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello, world!",
})
})
router.Run(":8080")
}
此代码创建了一个简单的API,该API在端口8080上听,并以“ Hello,World!”做出响应。当您向根端点提出get请求时。
接下来,我们将在API中添加JWT身份验证。我们将使用github.com/dgrijalva/jwt-go软件包来生成和验证JWTS。
package main
import (
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
var jwtKey = []byte("my_secret_key")
func main() {
router := gin.Default()
router.POST("/login", login)
auth := router.Group("/auth")
auth.Use(authMiddleware())
{
auth.GET("/hello", hello)
}
router.Run(":8080")
}
func login(c *gin.Context) {
var loginData struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
if err := c.ShouldBindJSON(&loginData); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if loginData.Username != "myuser" || loginData.Password != "mypassword" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid login credentials"})
return
}
expirationTime := time.Now().Add(5 * time.Minute)
claims := &jwt.StandardClaims{
ExpiresAt: expirationTime.Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString(jwtKey)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not generate token"})
return
}
c.JSON(http.StatusOK, gin.H{"token": tokenString})
}
func authMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.GetHeader("Authorization")
if tokenString == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header missing"})
return
}
token, err := jwt.ParseWithClaims(tokenString, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, jwt.ErrInvalidSigningMethod
}
return jwtKey, nil
})
if err != nil {
if err == jwt.ErrSignatureInvalid {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token signature"})
return
}
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
return
}
if !token.Valid {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
return
}
c.Next()
}
}
func hello(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "Hello, authenticated user!"})
}
让我们逐步浏览此代码。首先,我们定义一个将用于签名和验证JWT的jwtKey
变量。该键应保密,而不是与任何人共享。
接下来,我们定义两个端点:/login
和/auth/hello
。 /login
端点以JSON格式接受用户名和密码,检查它们是否有效,并在JWT中生成JWT。 /auth/hello
端点需要在请求的Authorization
标题中包含有效的JWT。
login
函数首先检查用户名和密码是否有效。如果是的话,它将创建一个新的JWT,其到期时间为5分钟,并以JSON格式返回客户。
authMiddleware
函数是一个中间件,可以检查请求的Authorization
标头中是否包含有效的JWT。如果存在有效的JWT,它将调用c.Next()
以允许请求继续进行。如果不存在有效的JWT或无效,则返回错误响应。
最后,hello
函数是一个受保护的端点,需要访问有效的JWT。如果存在有效的JWT,它将返回“您好,身份验证的用户!” json格式的消息。
让我们开始讨论我们用来在Golang API中实现JWT身份验证的jwt-go
软件包。该软件包提供了用于创建,解析和验证JWT的功能。
创建JWT时,我们首先创建一个StandardClaims
结构,该结构包括我们要在JWT有效载荷中包含的任何主张,例如到期时间。然后,我们使用jwt.NewWithClaims
函数创建一个新的JWT,并使用我们的jwtKey
变量签名。然后,随后的签名JWT包含在对客户端的响应中。
验证JWT时,我们首先从请求的Authorization
标头中提取JWT,然后使用jwt.ParseWithClaims
函数解析。我们将jwtKey
变量作为第二个参数传递给此函数,以验证JWT的签名。如果JWT有效并且尚未过期,我们致电c.Next()
以允许请求继续。如果JWT无效或已过期,我们返回错误响应。
重要的是要注意,应与HTTPS结合使用JWT,以确保它们安全地传输。 JWT也应保密,而不是与其他任何人共享。
除了jwt-go
软件包外,我们还使用了Gin
框架来创建Golang API。 Gin是一个轻巧的Web框架,可提供诸如路由,中间件和错误处理之类的功能。我们在API:/login
中定义了两个端点,如果用户提供有效的凭据,它将生成JWT,而/auth/hello
(需要有效的JWT)。
就是这样! 使用此代码,您创建了一个具有JWT身份验证的Golang API。当然,您可以自定义此代码以满足您的特定需求,但这应该给您一个很好的起点。