gin框架精通篇(三)

2024-05-28 05:04
文章标签 精通 框架 gin

本文主要是介绍gin框架精通篇(三),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

HMAC 签名

package mainimport ("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 stringjwt.StandardClaims
}var jwtKey = []byte("a_secret_key")func main() {r := gin.Default()r.POST("/getToken1", func(context *gin.Context) {var u HmacUsercontext.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 HmacUsercontext.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 mainimport ("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  []byteresPublicKey   []byteerr2_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 RsaUsercontext.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 mainimport ("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          erroreccPrivateKey *ecdsa.PrivateKeyeccPublicKey  *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 EcdsaUsererr := 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 EcdsaUsercontext.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 errorvar prk *ecdsa.PrivateKeyvar pub *ecdsa.PublicKeyvar curve elliptic.Curveswitch 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.PublicKeyreturn prk, pub, err
}

在这里插入图片描述

在这里插入图片描述

这篇关于gin框架精通篇(三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1009610

相关文章

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

Spring 框架之Springfox使用详解

《Spring框架之Springfox使用详解》Springfox是Spring框架的API文档工具,集成Swagger规范,自动生成文档并支持多语言/版本,模块化设计便于扩展,但存在版本兼容性、性... 目录核心功能工作原理模块化设计使用示例注意事项优缺点优点缺点总结适用场景建议总结Springfox 是

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Python的端到端测试框架SeleniumBase使用解读

《Python的端到端测试框架SeleniumBase使用解读》:本文主要介绍Python的端到端测试框架SeleniumBase使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全... 目录SeleniumBase详细介绍及用法指南什么是 SeleniumBase?SeleniumBase

Oracle 数据库数据操作如何精通 INSERT, UPDATE, DELETE

《Oracle数据库数据操作如何精通INSERT,UPDATE,DELETE》在Oracle数据库中,对表内数据进行增加、修改和删除操作是通过数据操作语言来完成的,下面给大家介绍Oracle数... 目录思维导图一、插入数据 (INSERT)1.1 插入单行数据,指定所有列的值语法:1.2 插入单行数据,指

MySQL DQL从入门到精通

《MySQLDQL从入门到精通》通过DQL,我们可以从数据库中检索出所需的数据,进行各种复杂的数据分析和处理,本文将深入探讨MySQLDQL的各个方面,帮助你全面掌握这一重要技能,感兴趣的朋友跟随小... 目录一、DQL 基础:SELECT 语句入门二、数据过滤:WHERE 子句的使用三、结果排序:ORDE

C++ HTTP框架推荐(特点及优势)

《C++HTTP框架推荐(特点及优势)》:本文主要介绍C++HTTP框架推荐的相关资料,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. Crow2. Drogon3. Pistache4. cpp-httplib5. Beast (Boos

SpringBoot基础框架详解

《SpringBoot基础框架详解》SpringBoot开发目的是为了简化Spring应用的创建、运行、调试和部署等,使用SpringBoot可以不用或者只需要很少的Spring配置就可以让企业项目快... 目录SpringBoot基础 – 框架介绍1.SpringBoot介绍1.1 概述1.2 核心功能2