gin框架實現簡單的jwt認證


之前的總結

之前自己總結過使用Python實現JWT認證的博客:關於跨域與同源策略、安全cookie、CSRF與JWT認證校驗看這一篇就夠了

參考博客

主要參考這篇博客實現的,自己親自動手實現一下,加深一下印象:https://www.liwenzhou.com/posts/Go/jwt_in_gin/

進階的模塊

GitHub上有一個進階的模塊,里面有refreshToken以及auth認證等說明:https://github.com/appleboy/gin-jwt

自己的練習

需要先下載 jwt-go 這個模塊:

go get github.com/dgrijalva/jwt-go 

gin框架中使用jwt認證代碼 

package t_ginProjets

import (
    "errors"
    "github.com/dgrijalva/jwt-go"
    "github.com/gin-gonic/gin"
    "net/http"
    "strings"
    "testing"
    "time"
)

// 用戶信息結構體
type User struct {
    Username string `json:"username"`
    Password string `json:"password"`
}

// MyClaims 自定義聲明結構體並內嵌jwt.StandardClaims
// jwt包自帶的jwt.StandardClaims只包含了官方字段
// 我們這里需要額外記錄一個username字段,所以要自定義結構體
// 如果想要保存更多信息,都可以添加到這個結構體中
type MyClaims struct {
    Username string `json:"username"`
    jwt.StandardClaims
}

// 定義JWT的過期時間 設置2小時
const TokenExpireDuration = time.Hour * 2

// 定義一個secret
var JWTSecret = []byte("GarfieldIsAHero!")

// 1、生成JWT
func GenToken(username string) (string, error) {

    c := MyClaims{
        "wanghw", // 自定義的字段
        jwt.StandardClaims{
            ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 過期時間
            Issuer:    "jwt_test",                                 // 簽發人
        },
    }
    // 使用指定的簽名方法創建簽名對象
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
    // 使用指定的secret簽名並獲取完整的編碼后的字符串token
    return token.SignedString(JWTSecret)
}

// 2、解析JWT
func ParseToken(tokenString string) (*MyClaims, error) {
    // 后面是一個匿名函數
    token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (i interface{}, err error) {
        return JWTSecret, nil
    })
    if err != nil {
        return nil, err
    }
    // 校驗token
    if claims, ok := token.Claims.(*MyClaims); ok && token.Valid {
        return claims, nil
    }
    return nil, errors.New("invalid token")
}

// 3、定義一條 authHandler用於token的認證
func authHandler(c *gin.Context) {
    // 用戶發送用戶名與密碼
    var user User
    // 獲取參數
    err := c.ShouldBind(&user)
    if err != nil {
        c.JSON(http.StatusOK, gin.H{
            "code": 2002,
            "msg":  "無效的參數",
        })
        c.Abort()
        return
    }

    // 校驗用戶名與密碼是否正確
    if user.Username != "whw" || user.Password != "666" {
        c.JSON(200, gin.H{
            "code": 2001,
            "msg":  "用戶名或密碼錯誤",
        })
        c.Abort()
        return
    }

    // 生成Token
    tokenString, _ := GenToken(user.Username)
    c.JSON(200, gin.H{
        "code": 2000,
        "msg":  "success",
        "data": gin.H{"token": tokenString, "tokenExpire": 7200},
    })
    return
}

// 4、實現校驗的中間件
// JWTAuthMiddleware 基於JWT的認證中間件
func JWTAuthMiddleware() func(c *gin.Context) {
    return func(c *gin.Context) {
        // 客戶端攜帶Token有三種方式 1.放在請求頭 2.放在請求體 3.放在URI
        // 這里假設Token放在Header的Authorization中,並使用Bearer開頭
        // 這里的具體實現方式要依據你的實際業務情況決定
        authHeader := c.Request.Header.Get("Authorization") // 獲取請求頭中的數據
        if authHeader == "" {
            c.JSON(http.StatusOK, gin.H{
                "code": 2003,
                "msg":  "請求頭中auth為空",
            })
            // 不進行下面的請求處理了!
            c.Abort()
            return
        }
        // 按空格分割
        parts := strings.SplitN(authHeader, " ", 2)
        if !(len(parts) == 2 && parts[0] == "Bearer") {
            c.JSON(http.StatusOK, gin.H{
                "code": 2004,
                "msg":  "請求頭中auth格式有誤",
            })
            // 不進行下面的請求處理了!
            c.Abort()
            return
        }
        // parts[1]是獲取到的tokenString,我們使用之前定義好的解析JWT的函數來解析它
        mc, err := ParseToken(parts[1])
        if err != nil {
            c.JSON(http.StatusOK, gin.H{
                "code": 2005,
                "msg":  "無效的Token",
            })
            // 不進行下面的請求處理了!
            c.Abort()
            return
        }
        // 將當前請求的username信息保存到請求的上下文c上
        c.Set("username", mc.Username)
        c.Next() // 后續的處理函數可以用過c.Get("username")來獲取當前請求的用戶信息
    }
}

// *** 開始測試
func TestJWTAuth(t *testing.T) {
    // 默認引擎
    r := gin.Default()

    // 注冊路由
    // 生成token的請求
    r.POST("/auth", authHandler)
    // home路由需要注冊認證中間件
    r.GET("/home", JWTAuthMiddleware(), homeHandler)

    // 啟動
    r.Run("127.0.0.1:9100")

}

// home路由
func homeHandler(c *gin.Context) {
    // 獲取參數
    username := c.MustGet("username").(string)

    // 返回響應
    c.JSON(http.StatusOK, gin.H{
        "code": 2000,
        "msg":  "success",
        "data": gin.H{"username": username},
    })
}
View Code

認證過程

啟動服務后,需要首先生成token,我這里使用postman測試:

生成token成功后,需要在auth頭中加入bearer token,token的具體值就是上面生成的那個:

~~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM