gin框架精通篇(三)

HMAC 签名

package main

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

type HmacUser struct {
	Id        string `json:"id"`
	Name      string `json:"name"`
	Telephone string `json:"telephone"`
	Password  string `json:"password"`
}

type MyClaims struct {
	UserId string
	jwt.StandardClaims
}

var jwtKey = []byte("a_secret_key")

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

	r.POST("/getToken1", func(context *gin.Context) {
		var u HmacUser
		context.Bind(&u)
		token, err := hmacReleaseToken(u)
		if err != nil {
			context.JSON(http.StatusInternalServerError, err)
		}
		context.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "token分发成功",
			"data": token,
		})
	})

	r.POST("/checkToken1", hmacAuthMiddleware(), func(context *gin.Context) {
		context.JSON(http.StatusOK, "验证成功")
	})

	r.Run(":9090")
}

func hmacAuthMiddleware() gin.HandlerFunc {
	return func(context *gin.Context) {
		auth := "fanfan"
		tokenString := context.GetHeader("Authorization")
		if tokenString == "" || !strings.HasPrefix(tokenString, auth+":") {
			context.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "前缀错误"})
			context.Abort()
			return
		}
		index := strings.Index(tokenString, auth+":")
		tokenString = tokenString[index+len(auth)+1:]
		token, claims, err := hmacParseToken(tokenString)

		if err != nil || !token.Valid {
			context.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "证书无效"})
			context.Abort()
			return
		}
		var u HmacUser
		context.Bind(&u)
		if u.Id != claims.UserId {
			context.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "用户不存在"})
			context.Abort()
			return
		}
		context.Next()
	}
}

func hmacParseToken(tokenString string) (*jwt.Token, *MyClaims, error) {
	claims := &MyClaims{}
	token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
		return jwtKey, nil
	})
	return token, claims, err
}

func hmacReleaseToken(u HmacUser) (string, error) {
	expirationTime := time.Now().Add(7 * 24 * time.Hour)
	claims := &MyClaims{
		UserId: u.Id,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expirationTime.Unix(),
			IssuedAt:  time.Now().Unix(),
			Issuer:    "fanfan",
			Subject:   "user token",
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenString, err := token.SignedString(jwtKey)
	if err != nil {
		return "", err
	}
	return tokenString, nil
}

在这里插入图片描述

在这里插入图片描述

RSA签名

rsa签名生成公钥、私钥:https://www.metools.info/code/c80.html

package main

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

type RsaUser struct {
	Id        string `json:"id"`
	Name      string `json:"name"`
	Telephone string `json:"telephone"`
	Password  string `json:"password"`
}

type RasClaims struct {
	UserId string `json:"user_id"`
	jwt.StandardClaims
}

var (
	resPrivateKey  []byte
	resPublicKey   []byte
	err2_1, err2_2 error
)

func init() {
	resPrivateKey, err2_1 = ioutil.ReadFile("./token/private.pem")
	resPublicKey, err2_2 = ioutil.ReadFile("./token/public.pem")
	if err2_1 != nil || err2_2 != nil {
		panic(fmt.Sprintf("打开密钥文件错误:%s,%s", err2_1, err2_2))
	}
}

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

	r.POST("/getToken2", func(context *gin.Context) {
		u := RsaUser{}
		err := context.Bind(&u)
		if err != nil {
			context.JSON(http.StatusBadRequest, "参数错误")
			return
		}
		token, err := resaReleaseToken(u)
		if err != nil {
			context.JSON(http.StatusBadRequest, "生成token错误")
			return
		}
		context.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "token分发成功",
			"data": token,
		})
	})

	r.POST("/checkToken2", rsaTokenMiddle(), func(context *gin.Context) {
		context.JSON(http.StatusOK, "验证成功")
	})

	r.Run(":9090")
}

func rsaTokenMiddle() gin.HandlerFunc {
	return func(context *gin.Context) {
		auth := "fanfan"
		tokenString := context.GetHeader("Authorization")
		if tokenString == "" || !strings.HasPrefix(tokenString, auth+":") {
			context.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "无效的token"})
			context.Abort()
			return
		}
		index := strings.Index(tokenString, auth+":")
		tokenString = tokenString[index+len(auth)+1:]
		claims, err := rsaJwtTokenRead(tokenString)
		if err != nil {
			context.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "证书无效"})
			context.Abort()
			return
		}
		claimsValue := claims.(jwt.MapClaims)
		if claimsValue["user_id"] == nil {
			context.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "用户不存在"})
			context.Abort()
			return
		}
		var u RsaUser
		context.Bind(&u)
		if u.Id != claimsValue["user_id"].(string) {
			context.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "用户不存在"})
			context.Abort()
			return
		}
		context.Next()
	}
}

func rsaJwtTokenRead(tokenString string) (interface{}, error) {
	pem, err := jwt.ParseRSAPublicKeyFromPEM(resPublicKey)
	if err != nil {
		return nil, err
	}
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		if _, OK := token.Method.(*jwt.SigningMethodRSA); !OK {
			return nil, fmt.Errorf("解析方法错误")
		}
		return pem, err
	})
	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		return claims, err
	}
	return nil, err
}

func resaReleaseToken(u RsaUser) (interface{}, error) {
	tokenGen, err := rasJwtTokenGen(u.Id)
	return tokenGen, err
}

func rasJwtTokenGen(id string) (interface{}, error) {
	private, err := jwt.ParseRSAPrivateKeyFromPEM(resPrivateKey)
	if err != nil {
		return nil, err
	}
	claims := &RasClaims{
		UserId: id,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Add(7 * 24 * time.Hour).Unix(),
			Issuer:    "fanfan",
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
	signedString, err := token.SignedString(private)
	return signedString, err
}

在这里插入图片描述

在这里插入图片描述

ECDSA签名

package main

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"errors"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"
	"time"
)

type EcdsaUser struct {
	Id        string `json:"id"`
	Name      string `json:"name"`
	Telephone string `json:"telephone"`
	Password  string `json:"password"`
}

type EcdsaClaims struct {
	UserId string `json:"user_id"`
	jwt.StandardClaims
}

var (
	err3          error
	eccPrivateKey *ecdsa.PrivateKey
	eccPublicKey  *ecdsa.PublicKey
)

func init() {
	eccPrivateKey, eccPublicKey, err3 = getEcdsaKey(2)
	if err3 != nil {
		panic(err3)
		return
	}
}

func ecdsaReleaseToken(u EcdsaUser) (interface{}, error) {
	claims := &EcdsaClaims{
		UserId: u.Id,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Add(7 * 24 * time.Hour).Unix(),
			Issuer:    "fanfan",
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodES256, claims)
	signedString, err := token.SignedString(eccPrivateKey)
	return signedString, err
}

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

	r.POST("/getToken3", func(context *gin.Context) {
		var u EcdsaUser
		err := context.Bind(&u)
		if err != nil {
			context.JSON(http.StatusInternalServerError, "参数错误")
		}
		token, err := ecdsaReleaseToken(u)
		if err != nil {
			context.JSON(http.StatusInternalServerError, err)
		}
		context.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "token分发成功",
			"data": token,
		})
	})

	r.POST("/checkToken3", ecdsaTokenMiddleware(), func(context *gin.Context) {
		context.JSON(http.StatusOK, "验证成功")
	})

	r.Run(":9090")
}

func ecdsaTokenMiddleware() gin.HandlerFunc {
	return func(context *gin.Context) {
		auth := "fanfan"
		tokenString := context.GetHeader("Authorization")
		if tokenString == "" || !strings.HasPrefix(tokenString, auth+":") {
			context.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "无效的token"})
			context.Abort()
			return
		}
		index := strings.Index(tokenString, auth+":")
		tokenString = tokenString[index+len(auth)+1:]
		claims, err := ecdsaJwtTokenRead(tokenString)
		if err != nil {
			context.AbortWithStatusJSON(http.StatusUnauthorized, err)
			return
		}
		claimsValue := claims.(jwt.MapClaims)
		if claimsValue["user_id"] == nil {
			context.AbortWithStatusJSON(http.StatusUnauthorized, "id不存在")
			return
		}
		var u EcdsaUser
		context.Bind(&u)
		if u.Id != claimsValue["user_id"] {
			context.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "用户不存在"})
			context.Abort()
			return
		}
		context.Next()
	}
}

func ecdsaJwtTokenRead(tokenString string) (interface{}, error) {
	myToken, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodECDSA); !ok {
			return nil, fmt.Errorf("无效的签名方法")
		}
		return eccPublicKey, nil
	})
	if claims, ok := myToken.Claims.(jwt.MapClaims); ok && myToken.Valid {
		return claims, nil
	}
	return nil, err
}

func getEcdsaKey(keyType int) (*ecdsa.PrivateKey, *ecdsa.PublicKey, error) {
	var err error
	var prk *ecdsa.PrivateKey
	var pub *ecdsa.PublicKey
	var curve elliptic.Curve
	switch keyType {
	case 1:
		curve = elliptic.P224()
	case 2:
		curve = elliptic.P256()
	case 3:
		curve = elliptic.P384()
	case 4:
		curve = elliptic.P521()
	default:
		err = errors.New("输入签名 key 类型错误!")
		return nil, nil, err
	}
	prk, err = ecdsa.GenerateKey(curve, rand.Reader)
	if err != nil {
		return nil, nil, err
	}
	pub = &prk.PublicKey
	return prk, pub, err
}

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值