所有文章 > API安全 > 在 Golang 中实现 JWT 令牌认证
在 Golang 中实现 JWT 令牌认证

在 Golang 中实现 JWT 令牌认证

JSON Web Tokens (JWT) 作为一种在 Web 应用程序中实现身份验证和授权机制的安全而有效的方法,已经获得了广泛的欢迎。在本文中,我们将探讨如何使用golang-jwt/jwt包在 Golang 中实现 JWT 令牌身份验证,并构建登录系统以保护受保护的路由。

先决条件

要学习本教程,您应该对 Go 编程有基本的了解,并在您的机器上安装了 Go。此外,您还应该有一个文本编辑器或一个用于编写 Go 代码的集成开发环境 (IDE)。

安装软件包

在开始实现 JWT 令牌认证之前,我们需要安装该golang-jwt/jwt软件包。打开终端或命令提示符并执行以下命令:

去获取 github.com/golang-jwt/jwt/v5

这将下载并安装该包,使其可供我们的应用程序使用。

创建 JWT 令牌

实现 JWT 令牌认证的第一步是创建并签名令牌。让我们创建一个生成新 JWT 令牌的函数:

包主导

入(
“fmt”
“github.com/golang-jwt/jwt/v5”
“time”


var secretKey = [] byte(“secret-key”)

func createToken (username字符串)(string,error){
token:= jwt.NewWithClaims(jwt.SigningMethodHS256,
jwt.MapClaims{
“username”:username,
“exp”:time.Now()。Add(time.Hour * 24).Unix(),
})

tokenString,err:= token.SignedString(secretKey)
如果err!= nil {
返回 “”,err
}

返回tokenString,nil
}

在上面的代码片段中,我们导入了必要的包,包括github.com/golang-jwt/jwt/v5。我们使用函数创建一个新的 JWT 令牌jwt.NewWithClaims()。我们将签名方法指定为HS256 以及相关信息,例如用户名和令牌过期时间。然后,我们使用密钥对令牌进行签名,并将生成的令牌作为字符串返回。

验证 JWT 令牌

一旦我们有了令牌,我们就需要在授予对受保护资源的访问权限之前验证其真实性。让我们创造验证并解析 JWT 令牌的函数:

func  verifyToken (tokenString string )  error {
token, err := jwt.Parse(tokenString, func (token *jwt.Token) ( interface {}, error ) {
return secretKey, nil
})

if err != nil {
return err
}

if !token.Valid {
return fmt.Errorf( "invalid token" )
}

return nil
}

在上面的代码片段中,我们使用jwt.Parse()函数来解析和验证令牌。我们提供了一个回调函数来检索用于签署令牌的密钥。如果令牌有效,我们将继续处理请求;否则,我们返回一个错误,表明令牌无效。

实现登录系统

为了保护受保护的路由,我们需要引入一个登录系统,用户可以在其中进行身份验证并获取 JWT 令牌。让我们创建一个登录端点,用户可以在其中提供他们的用户名和密码:

func  LoginHandler (w http.ResponseWriter, r *http.Request) {
w.Header().Set( "Content-Type" , "application/json" )

var u User
json.NewDecoder(r.Body).Decode(&u)
fmt.Printf( "用户请求值 %v" , u)

if u.Username == "Chek" && u.Password == "123456" {
tokenString, err := CreateToken(u.Username)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Errorf( "未找到用户名" )
}
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, tokenString)
return
} else {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprint(w, "无效凭据" )
}
}

在上面的代码片段中,我们定义了一个端点,该端点接受请求主体中包含和/login的 POST 请求。我们通过检查提供的凭据是否与预期值匹配来模拟用户身份验证。如果凭据有效,我们将使用该函数生成 JWT 令牌并将其作为响应返回。否则,我们返回适当的错误响应。usernamepasswordcreateToken()

确保受保护的路线

现在我们已经实现了登录系统并获得了 JWT 令牌,让我们修改受保护的路由以要求有效的 JWT 令牌进行访问:

func  ProtectedHandler (w http.ResponseWriter, r *http.Request) {
w.Header().Set( "Content-Type" , "application/json" )
tokenString := r.Header.Get( "Authorization" )
if tokenString == "" {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprint(w, "Missing authorization header" )
return
}
tokenString = tokenString[ len ( "Bearer " ):]

err := verifyToken(tokenString)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprint(w, "Invalid token" )
return
}

fmt.Fprint(w, "Welcome to the protected area" )

}

在上面的代码片段中,我们检查Authorization请求标头中是否存在有效的 JWT 令牌。如果令牌缺失或无效,我们将返回适当的错误响应。否则,我们将继续提供受保护的资源。

以下是完整代码

包主导

入(
“fmt”
“github.com/gorilla/mux”
“github.com/golang-jwt/jwt”
“net/http”
“encoding/json”
“time”


var secretKey = [] byte(“secret-key”)

func main () {
router:= mux.NewRouter()

router.HandleFunc(“/login”,login.LoginHandler)。方法(“POST”)
router.HandleFunc(“/protected”,login.ProtectedHandler)。方法(“GET”)

fmt.Println(“启动服务器”)
err:= http.ListenAndServe(“localhost:4000”,router)
if err!= nil {
fmt.Println(“无法启动服务器”,err)
}
}

func LoginHandler (w http.ResponseWriter,r *http.Request) {
w.Header().Set( "Content-Type" , "application/json" )

var u User
json.NewDecoder(r.Body).Decode(&u)
fmt.Printf( "用户请求值 %v" , u)

if u.Username == "Chek" && u.Password == "123456" {
tokenString, err := CreateToken(u.Username)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Errorf( "未找到用户名" )
}
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, tokenString)
return
} else {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprint(w, "无效凭据" )
}
}

func ProtectedHandler (w http.ResponseWriter, r *http.Request) {
w.Header().Set( "Content-Type" , "application/json" )
tokenString := r.Header.Get( "Authorization" )
如果tokenString == "" {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprint(w,“缺少授权标头”)
返回
}
tokenString = tokenString [ len(“Bearer”:]

err:= verifyToken(tokenString)
如果err!= nil{
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprint(w, "无效的令牌" )
return
}

fmt.Fprint(w, "欢迎来到保护区" )

}

func createToken (username string ) ( string , error ) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256,
jwt.MapClaims{
"username" : username,
"exp" : time.Now().Add(time.Hour * 24 ).Unix(),
})

tokenString, err := token.SignedString(secretKey)
if err != nil {
return "" , err
}

return tokenString, nil
}

func verifyToken (tokenString string ) error {
token, err := jwt.Parse(tokenString, func (token *jwt.Token) ( interface {},错误) {
返回secretKey,nil
})

如果err != nil {
返回err
}

如果!token.Valid {
返回fmt.Errorf(“无效令牌”)
}

返回 nil
}

请注意,我们还使用 创建了一个新的 HTTP 路由器。然后,我们使用定义了和端点的http.NewRouter()路由处理程序。最后,我们通过调用 启动了服务器。/login/protectedrouter.HandleFunc()http.ListenAndServe(":4000", router)

此设置允许/login端点处理登录过程并生成 JWT 令牌,而/protected端点在授予对受保护区域的访问权限之前验证 JWT 令牌。

我们可以使用Postman测试我们的应用程序,通过向登录端点发送 Post 请求http://localhost:4000/login,并使用我们的用户名和密码作为请求正文。

发布请求

响应主体返回一个 JWT 令牌eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTA4NzA2MjksInVzZXJuYW1lIjoiQ2hlayJ9.oPHtaTaIKwSuetkYpVwLMkKnCI-c9aGEKS5vFDBFl2Y

我们现在发送一个 GET 请求,并在授权标头中设置上述 JWT 令牌,以http://localhost:4000/protected访问受保护区域。

结论

在本文中,我们探讨了如何在 Golang 中实现 JWT 令牌身份验证。我们学习了如何创建和签署 JWT 令牌、验证其真实性以及构建登录系统以保护受保护的路由。通过将 JWT 令牌身份验证集成到您的 Go 应用程序中,您可以增强安全性并实现无状态身份验证机制。

#你可能也喜欢这些API文章!