go-gin集成jwt认证

今天趁热打铁,把cookie/session/jwt集成go-gin框架的认证方式,一鼓作气全code一遍,life is short, show you the code.

示例目录结构:

项目入口:

package main

import (
	"gin-any/api"
	"github.com/gin-gonic/gin"
)

func main()  {
	engine := gin.Default()

	engine.POST("/login", api.Login)

	engine.GET("/user", api.AuthJWTMiddleware(), api.User)

	engine.Run(":8080")
}

接口代码:

package api

import (
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"net/http"
)

type ReqParams struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

func User(ctx *gin.Context)  {
	ctx.JSON(200, gin.H{
		"code": 0,
		"msg": "success",
		"data": map[string]string{"user": "test"},
	})
}

func Login(ctx *gin.Context)  {
	var params ReqParams
	err := ctx.ShouldBindBodyWith(&params, binding.JSON)
	if err != nil {
		ctx.JSON(http.StatusOK, gin.H{"code": 1, "msg": "Invalid parameters."})
		return
	}
	if params.Username == "test" && params.Password == "123456" {
		// generate token
		token, _ := GenerateToken(params.Username)
		ctx.JSON(200, gin.H{
			"code": 0,
			"msg": "Login success",
			"data": gin.H{"token": token},
		})
		return
	}

	ctx.JSON(401, gin.H{
		"code": 1,
		"msg": "Login failed",
	})
}

中间件代码:

package api

import (
	"crypto/sha256"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/cookie"
	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"net/http"
	"strconv"
	"strings"
	"time"
)

func AuthJWTMiddleware() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		// extract jwt, Authorization: "Bearer " + token
		authHeader := ctx.Request.Header.Get("Authorization")
		if authHeader == "" { // return in advance
			ctx.JSON(http.StatusOK, gin.H{
				"code": 1,
				"msg": "Request header has no auth",
			})
			ctx.Abort()
			return
		}
		// parse jwt
		parts := strings.SplitN(authHeader, " ", 2)
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			ctx.JSON(http.StatusOK, gin.H{
				"code": 1,
				"msg": "Request header auth wrong format",
			})
			ctx.Abort()
			return
		}
		mc, err := ParseToken(parts[1])
		if err != nil {
			ctx.JSON(http.StatusOK, gin.H{
				"code": 1,
				"msg": "Invalid token",
			})
			ctx.Abort()
			return
		}
		// if needed, inject username into context
		ctx.Set("username", mc.Username)
		// pass request
		ctx.Next()
	}
}

type MyClaims struct {
	Username string `json:"username"`
	jwt.StandardClaims
}

const TokenExpireDuration = time.Second * 30

var MySecret = []byte("gin-jwt")

// generate token
func GenerateToken(username string) (string, error) {
	// create self claims
	c := MyClaims{
		username,
		jwt.StandardClaims{
			ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(),
			Issuer: "project",
		},
	}
	// specific sign method to create obj
	t := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
	return t.SignedString(MySecret)
}

// parse token
func ParseToken(tokenString string) (*MyClaims, error) {
	// parse token
	token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
		return MySecret, nil
	})
	if err != nil {
		return nil, err
	}
	if claims, ok := token.Claims.(*MyClaims); ok && token.Valid {
		return claims, nil
	}
	return nil, errors.New("Invalid token")
}

以下是postman测试情况:
login接口:

后续请求接口-过期token:

posted on 2022-11-03 18:15  进击的davis  阅读(335)  评论(0编辑  收藏  举报

导航