gin框架中JWT的使用

2,100 阅读2分钟

​gin框架中JWT的使用

JWT (JSON Web Token) 是一种规范。这个规范允许我们使用JWT在用户和服务器之间安全传递信息.jwt分3个部分,Header 头部、Payload 载荷、Signature 签名, 用 dot(.) 点分开。想要具体理解jwt的童鞋可以自行百度,这里就不再赘述。

首先我们需要引入jwt库

github.com/dgrijalva/jwt-go

package main
​
import (
  "errors"
  "github.com/dgrijalva/jwt-go"
  "github.com/gin-contrib/cors"
  "github.com/gin-gonic/gin"
  "net/http"
  "time"
)
​
const (
  ErrorServerBusy = "server is busy"
  ErrorReLogin    = "relogin"
)
​
type User struct {
  Id   int
  Name string
}
type JWTClaims struct {
  jwt.StandardClaims
  User User
}
​
var (
  Secret     = "123#111" //salt
  ExpireTime = 3600      //token expire time
)
​
//生成 jwt token
func genToken(user User) (string, error) {
  claims := &JWTClaims{
    User: user,
  }
  claims.IssuedAt = time.Now().Unix()
  claims.ExpiresAt = time.Now().Add(time.Second * time.Duration(ExpireTime)).Unix()
  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 verifyToken(ctx *gin.Context) (*JWTClaims, error) {
  strToken := ctx.Request.Header.Get("token")
  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)
  }
  return claims, nil
}
// 更新token
func refresh(c *gin.Context) (string, error) {
  claims, _ := verifyToken(c)
  return genToken(claims.User)
}
​
func jwtAuth(ctx *gin.Context) {
  if _, err := verifyToken(ctx); err == nil {
    ctx.Next()
  } else {
    ctx.JSON(http.StatusOK, gin.H{"code": 4001})
    ctx.Abort()
  }
}
​
func main() {
  router := gin.Default()
  //在web开发中,浏览器处于安全考虑会限制跨域请求。
  //我们采用前后端分离的方式写接口的时候服务器端要允许跨域请求
  //使用 cors中间件 允许跨域
  router.Use(cors.Default())
  router.GET("/login", func(ctx *gin.Context) {
    user := User{1, "hanyun"}
    singedToken, err := genToken(user)
    if err == nil {
      ctx.JSON(http.StatusOK, gin.H{"code": 0, "token": singedToken})
    } else {
      ctx.JSON(http.StatusOK, gin.H{"code": 1, "token": singedToken})
    }
  })
  //使用自定义的jwtAuth中间件
  router.Use(jwtAuth)
  router.GET("/user", func(context *gin.Context) {
    claims, _ := verifyToken(context)
    context.JSON(http.StatusOK, gin.H{"code": 0, "user": claims.User})
  })
  router.GET("/refresh", func(context *gin.Context) {
    singedToken, err:= refresh(context)
    if err == nil {
      context.JSON(http.StatusOK, gin.H{"code": 0, "token": singedToken})
    } else {
      context.JSON(http.StatusOK, gin.H{"code": 1, "token": singedToken})
    }
  })
  router.Run()
}


1、我们访问http://127.0.0.1:8080/login,获得token,结果如下

{
    "code": 0,
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODM2NzQ2MzEsImlhdCI6MTU4MzY3MTAzMSwiVXNlciI6eyJJZCI6MSwiTmFtZSI6Imhhbnl1biJ9fQ.kMmE3DWXvNOUVsuHWgrlbm2pbsOHmbMtyr-V6hVjQ4s"
}

2、访问http://127.0.0.1:8080/user,同时在header里面加入token,获得用户信息

postman示例如下

image

curl示例如下

curl --location --request GET 'http://127.0.0.1:8080/user' \
--header 'token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODM2NzQ2MzEsImlhdCI6MTU4MzY3MTAzMSwiVXNlciI6eyJJZCI6MSwiTmFtZSI6Imhhbnl1biJ9fQ.kMmE3DWXvNOUVsuHWgrlbm2pbsOHmbMtyr-V6hVjQ4s'

结果如下

{
    "code": 0,
    "user": {
        "Id": 1,
        "Name": "hanyun"
    }
}

3、刷新token,访问http://127.0.0.1:8080/refresh

postman示例如下

image

curl请求示例如下


curl --location --request GET 'http://127.0.0.1:8080/refresh' \
--header 'token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODM2NzQ2MzEsImlhdCI6MTU4MzY3MTAzMSwiVXNlciI6eyJJZCI6MSwiTmFtZSI6Imhhbnl1biJ9fQ.kMmE3DWXvNOUVsuHWgrlbm2pbsOHmbMtyr-V6hVjQ4s'


image

记着关注我哦

image