您好,登錄后才能下訂單哦!
這篇文章主要講解了“gin框架中怎么使用JWT”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“gin框架中怎么使用JWT”吧!
JWT全稱JSON Web Token是一種跨域認證解決方案,屬于一個開放的標準,它規定了一種Token實現方式,目前多用于前后端分離項目和OAuth4.0業務場景下。
在之前的一些web項目中,我們通常使用的是Cookie-Session
模式實現用戶認證。相關流程大致如下:
用戶在瀏覽器端填寫用戶名和密碼,并發送給服務端
服務端對用戶名和密碼校驗通過后會生成一份保存當前用戶相關信息的session數據和一個與之對應的標識(通常稱為session_id)
服務端返回響應時將上一步的session_id寫入用戶瀏覽器的Cookie
后續用戶來自該瀏覽器的每次請求都會自動攜帶包含session_id的Cookie
服務端通過請求中的session_id就能找到之前保存的該用戶那份session數據,從而獲取該用戶的相關信息。
這種方案依賴于客戶端(瀏覽器)保存Cookie,并且需要在服務端存儲用戶的session數據。
在移動互聯網時代,我們的用戶可能使用瀏覽器也可能使用APP來訪問我們的服務,我們的web應用可能是前后端分開部署在不同的端口,有時候我們還需要支持第三方登錄,這下Cookie-Session
的模式就有些力不從心了。
JWT就是一種基于Token的輕量級認證模式,服務端認證通過后,會生成一個JSON對象,經過簽名后得到一個Token(令牌)再發回給用戶,用戶后續請求只需要帶上這個Token,服務端解密之后就能獲取該用戶的相關信息了。
想要連接JWT的原理,推薦大家閱讀:阮一峰的JWT入門教程
我們在這里直接使用jwt-go
這個庫來實現我們生成JWT和解析JWT的功能。
我們需要定制自己的需求來決定JWT中保存哪些數據,比如我們規定在JWT中要存儲username
信息,那么我們就定義一個MyClaims
結構體如下:
import ( "github.com/dgrijalva/jwt-go" ) // 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 MySecret = []byte("夏天夏天悄悄過去")
// GenToken 生成JWT func GenToken(username string) (string, error) { // 創建一個我們自己的聲明 c := MyClaims{ "username", // 自定義字段 jwt.StandardClaims{ ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 過期時間 Issuer: "my-project", // 簽發人 }, } // 使用指定的簽名方法創建簽名對象 token := jwt.NewWithClaims(jwt.SigningMethodHS256, c) // 使用指定的secret簽名并獲得完整的編碼后的字符串token return token.SignedString(MySecret) }
// ParseToken 解析JWT func ParseToken(tokenString string) (*MyClaims, error) { // 解析token token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (i interface{}, err error) { return MySecret, nil }) if err != nil { return nil, err } if claims, ok := token.Claims.(*MyClaims); ok && token.Valid { // 校驗token return claims, nil } return nil, errors.New("invalid token") }
首先我們注冊一條路由/auth
,對外提供獲取Token的渠道:
r.POST("/auth", authHandler)
我們的authHandler
定義如下:
func authHandler(c *gin.Context) { // 用戶發送用戶名和密碼過來 var user UserInfo err := c.ShouldBind(&user) if err != nil { c.JSON(http.StatusOK, gin.H{ "code": 2001, "msg": "無效的參數", }) return } // 校驗用戶名和密碼是否正確 if user.Username == "q1mi" && user.Password == "q1mi123" { // 生成Token tokenString, _ := GenToken(user.Username) c.JSON(http.StatusOK, gin.H{ "code": 2000, "msg": "success", "data": gin.H{"token": tokenString}, }) return } c.JSON(http.StatusOK, gin.H{ "code": 2002, "msg": "鑒權失敗", }) return }
用戶通過上面的接口獲取Token之后,后續就會攜帶著Token再來請求我們的其他接口,這個時候就需要對這些請求的Token進行校驗操作了,很顯然我們應該實現一個檢驗Token的中間件,具體實現如下:
// 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")來獲取當前請求的用戶信息 } }
注冊一個/home
路由,發個請求驗證一下吧。
r.GET("/home", JWTAuthMiddleware(), homeHandler) 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}, }) }
感謝各位的閱讀,以上就是“gin框架中怎么使用JWT”的內容了,經過本文的學習后,相信大家對gin框架中怎么使用JWT這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。