欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

gin框架中使用JWT的定義需求及解析

 更新時(shí)間:2022年04月16日 13:27:31   作者:Jeff的技術(shù)棧  
這篇文章主要為介紹了gin框架中使用JWT的定義需求及解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪

什么是JWT?

JWT全稱JSON Web Token是一種跨域認(rèn)證解決方案,屬于一個(gè)開放的標(biāo)準(zhǔn),它規(guī)定了一種Token實(shí)現(xiàn)方式,目前多用于前后端分離項(xiàng)目和OAuth3.0業(yè)務(wù)場(chǎng)景下。

為什么需要JWT?

在之前的一些web項(xiàng)目中,我們通常使用的是Cookie-Session模式實(shí)現(xiàn)用戶認(rèn)證。相關(guān)流程大致如下:

  • 用戶在瀏覽器端填寫用戶名和密碼,并發(fā)送給服務(wù)端
  • 服務(wù)端對(duì)用戶名和密碼校驗(yàn)通過后會(huì)生成一份保存當(dāng)前用戶相關(guān)信息的session數(shù)據(jù)和一個(gè)與之對(duì)應(yīng)的標(biāo)識(shí)(通常稱為session_id)
  • 服務(wù)端返回響應(yīng)時(shí)將上一步的session_id寫入用戶瀏覽器的Cookie
  • 后續(xù)用戶來自該瀏覽器的每次請(qǐng)求都會(huì)自動(dòng)攜帶包含session_id的Cookie
  • 服務(wù)端通過請(qǐng)求中的session_id就能找到之前保存的該用戶那份session數(shù)據(jù),從而獲取該用戶的相關(guān)信息。

這種方案依賴于客戶端(瀏覽器)保存Cookie,并且需要在服務(wù)端存儲(chǔ)用戶的session數(shù)據(jù)。

在移動(dòng)互聯(lián)網(wǎng)時(shí)代,我們的用戶可能使用瀏覽器也可能使用APP來訪問我們的服務(wù),我們的web應(yīng)用可能是前后端分開部署在不同的端口,有時(shí)候我們還需要支持第三方登錄,這下Cookie-Session的模式就有些力不從心了。

JWT就是一種基于Token的輕量級(jí)認(rèn)證模式,服務(wù)端認(rèn)證通過后,會(huì)生成一個(gè)JSON對(duì)象,經(jīng)過簽名后得到一個(gè)Token(令牌)再發(fā)回給用戶,用戶后續(xù)請(qǐng)求只需要帶上這個(gè)Token,服務(wù)端解密之后就能獲取該用戶的相關(guān)信息了。

想要連接JWT的原理,推薦大家閱讀:JWT入門教程

生成JWT和解析JWT

我們?cè)谶@里直接使用jwt-go這個(gè)庫(kù)來實(shí)現(xiàn)我們生成JWT和解析JWT的功能。

定義需求

我們需要定制自己的需求來決定JWT中保存哪些數(shù)據(jù),比如我們規(guī)定在JWT中要存儲(chǔ)username信息,那么我們就定義一個(gè)MyClaims結(jié)構(gòu)體如下:

import (
	"github.com/dgrijalva/jwt-go"
)
// MyClaims 自定義聲明結(jié)構(gòu)體并內(nèi)嵌jwt.StandardClaims
// jwt包自帶的jwt.StandardClaims只包含了官方字段
// 我們這里需要額外記錄一個(gè)username字段,所以要自定義結(jié)構(gòu)體
// 如果想要保存更多信息,都可以添加到這個(gè)結(jié)構(gòu)體中
type MyClaims struct {
	Username string `json:"username"`
	jwt.StandardClaims
}

然后我們定義JWT的過期時(shí)間,這里以2小時(shí)為例:

const TokenExpireDuration = time.Hour * 2

接下來還需要定義Secret:

var MySecret = []byte("夏天夏天悄悄過去")

生成JWT

// GenToken 生成JWT
func GenToken(username string) (string, error) {
	// 創(chuàng)建一個(gè)我們自己的聲明
	c := MyClaims{
		"username", // 自定義字段
		jwt.StandardClaims{
			ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 過期時(shí)間
			Issuer:    "my-project",                               // 簽發(fā)人
		},
	}
	// 使用指定的簽名方法創(chuàng)建簽名對(duì)象
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
	// 使用指定的secret簽名并獲得完整的編碼后的字符串token
	return token.SignedString(MySecret)
}

解析JWT

// 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 { // 校驗(yàn)token
		return claims, nil
	}
	return nil, errors.New("invalid token")
}

在gin框架中使用JWT

首先我們注冊(cè)一條路由/auth,對(duì)外提供獲取Token的渠道:

r.POST("/auth", authHandler)

我們的authHandler定義如下:

func authHandler(c *gin.Context) {
	// 用戶發(fā)送用戶名和密碼過來
	var user UserInfo
	err := c.ShouldBind(&user)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": 2001,
			"msg":  "無效的參數(shù)",
		})
		return
	}
	// 校驗(yàn)用戶名和密碼是否正確
	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":  "鑒權(quán)失敗",
	})
	return
}

用戶通過上面的接口獲取Token之后,后續(xù)就會(huì)攜帶著Token再來請(qǐng)求我們的其他接口,這個(gè)時(shí)候就需要對(duì)這些請(qǐng)求的Token進(jìn)行校驗(yàn)操作了,很顯然我們應(yīng)該實(shí)現(xiàn)一個(gè)檢驗(yàn)Token的中間件,具體實(shí)現(xiàn)如下:

// JWTAuthMiddleware 基于JWT的認(rèn)證中間件
func JWTAuthMiddleware() func(c *gin.Context) {
	return func(c *gin.Context) {
		// 客戶端攜帶Token有三種方式 1.放在請(qǐng)求頭 2.放在請(qǐng)求體 3.放在URI
		// 這里假設(shè)Token放在Header的Authorization中,并使用Bearer開頭
		// 這里的具體實(shí)現(xiàn)方式要依據(jù)你的實(shí)際業(yè)務(wù)情況決定
		authHeader := c.Request.Header.Get("Authorization")
		if authHeader == "" {
			c.JSON(http.StatusOK, gin.H{
				"code": 2003,
				"msg":  "請(qǐng)求頭中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":  "請(qǐng)求頭中auth格式有誤",
			})
			c.Abort()
			return
		}
		// parts[1]是獲取到的tokenString,我們使用之前定義好的解析JWT的函數(shù)來解析它
		mc, err := ParseToken(parts[1])
		if err != nil {
			c.JSON(http.StatusOK, gin.H{
				"code": 2005,
				"msg":  "無效的Token",
			})
			c.Abort()
			return
		}
		// 將當(dāng)前請(qǐng)求的username信息保存到請(qǐng)求的上下文c上
		c.Set("username", mc.Username)
		c.Next() // 后續(xù)的處理函數(shù)可以用過c.Get("username")來獲取當(dāng)前請(qǐng)求的用戶信息
	}
}

注冊(cè)一個(gè)/home路由,發(fā)個(gè)請(qǐng)求驗(yàn)證一下吧。

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},
	})
}

如果不想自己實(shí)現(xiàn)上述功能,你也可以使用Github上別人封裝好的包。

以上就是gin框架中使用JWT的定義需求及解析的詳細(xì)內(nèi)容,更多關(guān)于gin框架中使用JWT的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go泛型的理解和使用小結(jié)

    Go泛型的理解和使用小結(jié)

    泛型是一種非常強(qiáng)大的編程技術(shù),可以提高代碼的復(fù)用性和可讀性,通過泛型容器和類型參數(shù)化,Go語(yǔ)言中的泛型可以實(shí)現(xiàn)更加靈活和通用的編程,提高代碼的復(fù)用性和可維護(hù)性,本文給大家介紹Go泛型的理解和使用,感興趣的朋友一起看看吧
    2023-12-12
  • Go語(yǔ)言高效I/O并發(fā)處理雙緩沖和Exchanger模式實(shí)例探索

    Go語(yǔ)言高效I/O并發(fā)處理雙緩沖和Exchanger模式實(shí)例探索

    這篇文章主要介紹了Go語(yǔ)言高效I/O并發(fā)處理雙緩沖和Exchanger模式實(shí)例探索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • 一文詳細(xì)談?wù)凣oLang的panic和error

    一文詳細(xì)談?wù)凣oLang的panic和error

    說是初識(shí),并不是說第一次使用error和panic包,而是第一次特地去了解golang中的這兩個(gè)機(jī)制,下面這篇文章主要給大家介紹了關(guān)于如何通過一文詳細(xì)談?wù)凣oLang中panic和error的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • 探索Golang實(shí)現(xiàn)Redis持久化AOF實(shí)例

    探索Golang實(shí)現(xiàn)Redis持久化AOF實(shí)例

    這篇文章主要為大家介紹了Golang實(shí)現(xiàn)Redis持久化AOF實(shí)例探索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Go 結(jié)構(gòu)體、數(shù)組、字典和 json 字符串的相互轉(zhuǎn)換方法

    Go 結(jié)構(gòu)體、數(shù)組、字典和 json 字符串的相互轉(zhuǎn)換方法

    今天小編就為大家分享一篇Go 結(jié)構(gòu)體、數(shù)組、字典和 json 字符串的相互轉(zhuǎn)換方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • Go語(yǔ)言結(jié)構(gòu)體定義和使用方法

    Go語(yǔ)言結(jié)構(gòu)體定義和使用方法

    這篇文章主要介紹了Go語(yǔ)言結(jié)構(gòu)體定義和使用方法,以實(shí)例形式分析了Go語(yǔ)言中結(jié)構(gòu)體的定義和使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • Go gorilla/sessions庫(kù)安裝使用

    Go gorilla/sessions庫(kù)安裝使用

    這篇文章主要為大家介紹了Go gorilla/sessions庫(kù)安裝使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Golang中的sync包的WaitGroup操作

    Golang中的sync包的WaitGroup操作

    這篇文章主要介紹了Golang中的sync包的WaitGroup操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • golang?http請(qǐng)求未釋放造成的錯(cuò)誤問題

    golang?http請(qǐng)求未釋放造成的錯(cuò)誤問題

    這篇文章主要介紹了golang?http請(qǐng)求未釋放造成的錯(cuò)誤問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Go語(yǔ)言常見錯(cuò)誤之將接口定義在實(shí)現(xiàn)方

    Go語(yǔ)言常見錯(cuò)誤之將接口定義在實(shí)現(xiàn)方

    在Go中,接口起到一個(gè)十分關(guān)鍵的角色,它們提供了一種方式來定義對(duì)象的行為,而不需要知道對(duì)象的具體實(shí)現(xiàn),一個(gè)常見的錯(cuò)誤是在實(shí)現(xiàn)方而不是使用方定義接口,本文將詳細(xì)探討為何這樣做是一個(gè)錯(cuò)誤,以及如何避免它
    2024-01-01

最新評(píng)論