今天趁热打铁,把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(¶ms, 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: