gin框架教程三:JWT的使用


gin框架教程代碼地址:
https://github.com/jiujuan/gin-tutorial

JWT介紹

JWT (JSON Web Token) 是一種規范。這個規范允許我們使用JWT在用戶和服務器之間安全傳遞信息.

JWT的組成:

jwt分3個部分,Header 頭部、Payload 載荷、Signature 簽名, 用 dot(.) 點分開
一般像下面這個樣子:
xxxx.yyyy.zzzz

一般表示算法和類型

{
  "alg": "HS256",
  "typ": "JWT"
}

JSON一般都會經過Base64Url編碼

Payload:

payload包含claims, claims一般包含實體信息(user信息等)和額外的信息。其中claims又分3種類型:
Registered claims: 這個推薦設置的選項,但不是強制的。 它提供了一些有用的信息,iss (issuer), exp (expiration time), sub (subject), aud(audience), and others
Public claims:在使用JWTs時可以被定義。
Private claims:用戶自定義的一些信息

example playload:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

也會經過base64編碼

Signature:

創建一個簽名,我們要使用到header,payload 和 secret,在用算法計算他們
比如用 hmac sha256 算法:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

計算出來長這個樣子:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjY1OTI3MjYsImlhdCI6MTU2NjU1NjcyNiwidXNlcl9pZCI6MSwicGFzc3dvcmQiOiIxMTEiLCJ1c2VybmFtZSI6InRvbSIsImZ1bGxfbmFtZSI6InRvbSIsInBlcm1pc3Npb25zIjpbXX0.HpkWP4CqlZBt-Ys_QYNs4yPd1GaR4oGxOeJU4In9co8

更多更詳細介紹請參閱:https://jwt.io/introduction/

Go example

使用的go jwt庫: https://github.com/dgrijalva/jwt-go,這個庫有6k多的start,確實是很受歡迎,所以用這個庫來寫demo

demo例子:

package main

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

const (
    ErrorServerBusy = "server is busy"
    ErrorReLogin = "relogin"
)

type JWTClaims struct {
    jwt.StandardClaims
    UserID int `json:"user_id"`
    Password string `json:"password"`
    Username string `json:"username"`
}

var (
    Secret = "123#111"  //salt
    ExpireTime = 3600  //token expire time
)

func main() {
    r := gin.Default()
    r.GET("/login/:username/:password", login)
    r.GET("/verify/:token", verify)
    r.GET("/refresh/:token", refresh)
    r.GET("/sayHello/:token", sayHello)
    _ = r.Run(":8000")
}

//generate jwt token
func genToken(claims *JWTClaims) (string, error) {
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    signedToken, err := token.SignedString([]byte(Secret))
    if err != nil {
        return "", errors.New(ErrorServerBusy)
    }
    return signedToken, nil
}

//登錄,獲取jwt token
func login(c *gin.Context) {
    username := c.Param("username")
    password := c.Param("password")
    claims := &JWTClaims{
        UserID: 1,
        Username: username,
        Password: password,
    }
    claims.IssuedAt = time.Now().Unix()
    claims.ExpiresAt = time.Now().Add(time.Second * time.Duration(ExpireTime)).Unix()
    singedToken, err := genToken(claims)
    if err != nil {
        c.String(http.StatusNotFound, err.Error())
        return
    }
    c.String(http.StatusOK, singedToken)
}

//驗證jwt token
func verifyAction(strToken string) (*JWTClaims, error) {
    token, err := jwt.ParseWithClaims(strToken, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
        return []byte(Secret), nil
    })
    if err != nil {
        return nil, errors.New(ErrorServerBusy)
    }

    claims, ok := token.Claims.(*JWTClaims)
    if !ok {
        return nil, errors.New(ErrorReLogin)
    }
    if err := token.Claims.Valid(); err != nil {
        return nil, errors.New(ErrorReLogin)
    }

    fmt.Println("verify")
    return claims, nil
}

func sayHello(c *gin.Context) {
    strToken := c.Param("token")
    claim, err := verifyAction(strToken)
    if err != nil {
        c.String(http.StatusNotFound, err.Error())
    }
    c.String(http.StatusOK, "hello, ", claim.Username)
}

func verify(c *gin.Context) {
    strToken := c.Param("token")
    claim, err := verifyAction(strToken)
    if err != nil {
        c.String(http.StatusNotFound, err.Error())
        return
    }
    c.String(http.StatusOK, "verify: ", claim.Username)
}

func refresh(c *gin.Context) {
    strToken := c.Param("token")
    claims, err := verifyAction(strToken)
    if err != nil {
        c.String(http.StatusNotFound, err.Error())
        return
    }
    claims.ExpiresAt = time.Now().Unix() + (claims.ExpiresAt - claims.IssuedAt)
    signedToken, err := genToken(claims)
    if err != nil {
        c.String(http.StatusNotFound, err.Error())
        return
    }
    c.String(http.StatusOK, signedToken, ", ", claims.ExpiresAt)
}


JWT資源

對於jwt的了解: https://jwt.io
jwt介紹:https://jwt.io/introduction/
rfc: https://tools.ietf.org/html/rfc7519
jwt方法參數定義的介紹:https://www.iana.org/assignments/jwt/jwt.xhtml
jwt handbook: https://auth0.com/resources/ebooks/jwt-handbook

JWT各種庫:https://jwt.io/#libraries


免責聲明!

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



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