亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

GoLang?jwt無感刷新與SSO單點登錄限制解除的方法是什么

發布時間:2023-03-31 15:07:20 來源:億速云 閱讀:119 作者:iii 欄目:開發技術

這篇文章主要介紹了GoLang jwt無感刷新與SSO單點登錄限制解除的方法是什么的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇GoLang jwt無感刷新與SSO單點登錄限制解除的方法是什么文章都會有所收獲,下面我們一起來看看吧。

    為什么使用JWT

    Jwt提供了生成token以及token驗證的方法,而token是一種不用存儲在服務端,只需要由用戶攜帶即可實現認證的一種方式。在介紹JWT之前,我們也應該先了解cookiesession

    Cookie和Session

    為每一位用戶設定一個SessionID,每次都需要對該SessionID進行比對。這個SessionID可能會保存在Cookie中,安全性不高,并且容易過期(一般session的過期時間都為30分鐘)。由于cookiesession需要保存在服務端,當用戶量非常大的時候,服務端的負載就會越來越大。甚至有因此崩潰的可能。所以采用token認證的方式。

    token (header.payload.signature)

    每個用戶在進行登錄的時候如果登錄信息正確就會收到服務端頒發的令牌token。當用戶每次進行請求時都會攜帶一個token。該token會在服務端進行校驗處理,復雜一點還需要經過一系列中間件的處理,確認token格式和參數是否正確。如果一切正常就需要對該用戶的本次操作進行放行。

    token 安全性

    如果token被非用戶人員獲取到,由于token已經頒發,在此token生效期間服務端無法對其進行解除,因為它并不在服務端內部進行保存。也就是說服務端的token一旦頒發就無法取消。

    基于token安全性的處理

    access token 和 refresh token

    以下access token簡稱 atokenrefresh token 簡稱 rtoken。無感刷新方式。

    在用戶登錄的時候頒發兩個token,atokenrtokenatoken 的有效期很短,根據業務實際需求可以自定義。一般設置為10分鐘足夠。rtoken有效期較長,一般可以設置為一星期或者一個月,根據實際業務需求可以自行定義。(根據查詢資料得知 rtoken需要進行client-sercet才能有效)。當atoken過期之后可以通過rtoken進行刷新,但是rtoken過期之后,只能重新登錄來獲取。

    atoken丟失之后沒關系,因為它有效期很短。當rtoken丟失之后也沒關系,因為他需要配合client-sercet才能使用。

    客戶端與服務端基于無感刷新流程圖

    GoLang?jwt無感刷新與SSO單點登錄限制解除的方法是什么

    golang實現atoken和rtoken

    引入jwt庫 go get -u github.com/golang-jwt/jwt/v4

    頒發token

    // GenToken 頒發token access token 和 refresh token
    func GenToken(UserID int64, Username string) (atoken, rtoken string, err error) {
    	rc := jwt.RegisteredClaims{
    		ExpiresAt: getJWTTime(ATokenExpiredDuration),
    		Issuer:    TokenIssuer,
    	}
    	at := MyClaim{
    		UserID,
    		Username,
    		rc,
    	}
    	atoken, err = jwt.NewWithClaims(jwt.SigningMethodHS256, at).SignedString(mySecret)
    	// refresh token 不需要保存任何用戶信息
    	rt := rc
    	rt.ExpiresAt = getJWTTime(RTokenExpiredDuration)
    	rtoken, err = jwt.NewWithClaims(jwt.SigningMethodHS256, rt).SignedString(mySecret)
    	return
    }

    在驗證用戶登錄之后,根據傳入的UID和Uname,生成atokenrtoken。在頒發token中可以規定token的過期時間

    func (t *Token) SignedString(key interface{}) (string, error)
    SignedString creates and returns a complete, signed JWT. The token is signed using the SigningMethod specified in the token.

    SignedString該方法主要用于token的數字簽名

    校驗token

    // VerifyToken 驗證Token
    func VerifyToken(tokenID string) (*MyClaim, error) {
    	var myc = new(MyClaim)
    	token, err := jwt.ParseWithClaims(tokenID, myc, keyFunc)
    	if err != nil {
    		return nil, err
    	}
    	if !token.Valid {
    		return nil, ErrorInvalidToken
    	}
    	return myc, nil
    }

    根據傳入的token值來判斷是否有錯誤,如果錯誤為無效,說明token格式不正確。然后校驗token是否過期。

    無感刷新token

    // RefreshToken 通過 refresh token 刷新 atoken
    func RefreshToken(atoken, rtoken string) (newAtoken, newRtoken string, err error) {
    	// rtoken 無效直接返回
    	if _, err = jwt.Parse(rtoken, keyFunc); err != nil {
    		return
    	}
    	// 從舊access token 中解析出claims數據
    	var claim MyClaim
    	_, err = jwt.ParseWithClaims(atoken, &claim, keyFunc)
    	// 判斷錯誤是不是因為access token 正常過期導致的
    	v, _ := err.(*jwt.ValidationError)
    	if v.Errors == jwt.ValidationErrorExpired {
    		return GenToken(claim.UserID, claim.Username)
    	}
    	return
    }

    注釋已經寫得很明白了,會根據舊的atoken和rtoken來返回新token。

    完整實現代碼

    package main
    import (
    	"errors"
    	"time"
    	"github.com/golang-jwt/jwt/v4"
    )
    const (
    	ATokenExpiredDuration  = 2 * time.Hour
    	RTokenExpiredDuration  = 30 * 24 * time.Hour
    	TokenIssuer            = ""
    )
    var (
    	mySecret          = []byte("xxxx")
    	ErrorInvalidToken = errors.New("verify Token Failed")
    )
    type MyClaim struct {
    	UserID   int64  `json:"user_id"`
    	Username string `json:"username"`
    	jwt.RegisteredClaims
    }
    func getJWTTime(t time.Duration) *jwt.NumericDate {
    	return jwt.NewNumericDate(time.Now().Add(t))
    }
    func keyFunc(token *jwt.Token) (interface{}, error) {
    	return mySecret, nil
    }
    // GenToken 頒發token access token 和 refresh token
    func GenToken(UserID int64, Username string) (atoken, rtoken string, err error) {
    	rc := jwt.RegisteredClaims{
    		ExpiresAt: getJWTTime(ATokenExpiredDuration),
    		Issuer:    TokenIssuer,
    	}
    	at := MyClaim{
    		UserID,
    		Username,
    		rc,
    	}
    	atoken, err = jwt.NewWithClaims(jwt.SigningMethodHS256, at).SignedString(mySecret)
    	// refresh token 不需要保存任何用戶信息
    	rt := rc
    	rt.ExpiresAt = getJWTTime(RTokenExpiredDuration)
    	rtoken, err = jwt.NewWithClaims(jwt.SigningMethodHS256, rt).SignedString(mySecret)
    	return
    }
    // VerifyToken 驗證Token
    func VerifyToken(tokenID string) (*MyClaim, error) {
    	var myc = new(MyClaim)
    	token, err := jwt.ParseWithClaims(tokenID, myc, keyFunc)
    	if err != nil {
    		return nil, err
    	}
    	if !token.Valid {
    		err = ErrorInvalidToken
    		return nil, err
    	}
    	return myc, nil
    }
    // RefreshToken 通過 refresh token 刷新 atoken
    func RefreshToken(atoken, rtoken string) (newAtoken, newRtoken string, err error) {
    	// rtoken 無效直接返回
    	if _, err = jwt.Parse(rtoken, keyFunc); err != nil {
    		return
    	}
    	// 從舊access token 中解析出claims數據
    	var claim MyClaim
    	_, err = jwt.ParseWithClaims(atoken, &claim, keyFunc)
    	// 判斷錯誤是不是因為access token 正常過期導致的
    	v, _ := err.(*jwt.ValidationError)
    	if v.Errors == jwt.ValidationErrorExpired {
    		return GenToken(claim.UserID, claim.Username)
    	}
    	return
    }

    SSO(Single Sign On)單用戶登錄以及無感刷新token

    實現思路

    因為token是由服務端頒發并且每次用戶的操作都要在服務端校驗token的有效性。因此兩個用戶在不同時間段登錄同一個賬號,那么他們的token肯定會因為時間而有所差別。我們可以將token存放在redis中,與用戶ID進行key-value綁定。如果通過userID查詢到的token不同,那么說明這個用戶的token已經被更換(該賬號又被登錄了)或者token錯誤。就需要重新進行登錄操作。

    實戰代碼

    // parts[1]是獲取到的atoken,我們使用之前定義好的解析JWT的函數來解析它
    mc, err := jwt.VerifyToken(parts[1])
    if err != nil {
        // 如果解析失敗,可能是因為token過期,可以進入refreshToken進行判斷
       if newAtoken, newRtoken, err := jwt.RefreshToken(parts[1],rtoken); err == nil {
           // 如果無錯誤,就更新redis中的token
          if err = redis.SetSingleUserToken(mc.Username, newAtoken); err == nil {
              // 這里根據需求返回給前端,由前端進行處理
             c.Writer.Header().Set("newAtoken", newAtoken)
             c.Writer.Header().Set("newRtoken", newRtoken)
             // 如果無錯誤,請求繼續
              c.Next()
          }
       }
        // 這里使用的是gin框架, 如果有錯誤直接阻止并返回
       c.Abort()
       return
    }
    // 如果解析成功,就在redis中進行判斷,是否單用戶登錄
    // 通過獲取redis中的token來校驗是否單用戶登錄
    token, err := redis.GetSingleUserToken(mc.Username)
    if err != nil {
       serializer.ResponseError(c, e.CodeServerBusy)
       c.Abort()
       return
    }

    判斷過程

    • 請求從前端傳來,經過認證中間件進行校驗token,如果沒有問題就進行redis單用戶校驗。

    • 如果有問題,可能是token過期。進行無感刷新,如果刷新成功將新token設置在header中,請求繼續

    • 如果無感刷新失敗請求阻止。

    關于“GoLang jwt無感刷新與SSO單點登錄限制解除的方法是什么”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“GoLang jwt無感刷新與SSO單點登錄限制解除的方法是什么”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    沈丘县| 宜都市| 宝丰县| 阿巴嘎旗| 团风县| 荣昌县| 利川市| 宾川县| 金阳县| 潢川县| 齐齐哈尔市| 衡阳市| 红安县| 肥西县| 酉阳| 甘洛县| 孙吴县| 玉门市| 黄山市| 广安市| 承德市| 阳春市| 伊春市| 惠安县| 会宁县| 定南县| 台前县| 三门峡市| 清镇市| 合作市| 海晏县| 璧山县| 许昌县| 吉林市| 黄陵县| 秦安县| 吉安市| 张北县| 稻城县| 德州市| 东宁县|