zoukankan      html  css  js  c++  java
  • gin框架实现简单的jwt认证

    之前的总结

    之前自己总结过使用Python实现JWT认证的博客:关于跨域与同源策略、安全cookie、CSRF与JWT认证校验看这一篇就够了

    参考博客

    主要参考这篇博客实现的,自己亲自动手实现一下,加深一下印象:https://www.liwenzhou.com/posts/Go/jwt_in_gin/

    进阶的模块

    GitHub上有一个进阶的模块,里面有refreshToken以及auth认证等说明:https://github.com/appleboy/gin-jwt

    自己的练习

    需要先下载 jwt-go 这个模块:

    go get github.com/dgrijalva/jwt-go 

    gin框架中使用jwt认证代码 

    package t_ginProjets
    
    import (
        "errors"
        "github.com/dgrijalva/jwt-go"
        "github.com/gin-gonic/gin"
        "net/http"
        "strings"
        "testing"
        "time"
    )
    
    // 用户信息结构体
    type User struct {
        Username string `json:"username"`
        Password string `json:"password"`
    }
    
    // MyClaims 自定义声明结构体并内嵌jwt.StandardClaims
    // jwt包自带的jwt.StandardClaims只包含了官方字段
    // 我们这里需要额外记录一个username字段,所以要自定义结构体
    // 如果想要保存更多信息,都可以添加到这个结构体中
    type MyClaims struct {
        Username string `json:"username"`
        jwt.StandardClaims
    }
    
    // 定义JWT的过期时间 设置2小时
    const TokenExpireDuration = time.Hour * 2
    
    // 定义一个secret
    var JWTSecret = []byte("GarfieldIsAHero!")
    
    // 1、生成JWT
    func GenToken(username string) (string, error) {
    
        c := MyClaims{
            "wanghw", // 自定义的字段
            jwt.StandardClaims{
                ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 过期时间
                Issuer:    "jwt_test",                                 // 签发人
            },
        }
        // 使用指定的签名方法创建签名对象
        token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
        // 使用指定的secret签名并获取完整的编码后的字符串token
        return token.SignedString(JWTSecret)
    }
    
    // 2、解析JWT
    func ParseToken(tokenString string) (*MyClaims, error) {
        // 后面是一个匿名函数
        token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (i interface{}, err error) {
            return JWTSecret, nil
        })
        if err != nil {
            return nil, err
        }
        // 校验token
        if claims, ok := token.Claims.(*MyClaims); ok && token.Valid {
            return claims, nil
        }
        return nil, errors.New("invalid token")
    }
    
    // 3、定义一条 authHandler用于token的认证
    func authHandler(c *gin.Context) {
        // 用户发送用户名与密码
        var user User
        // 获取参数
        err := c.ShouldBind(&user)
        if err != nil {
            c.JSON(http.StatusOK, gin.H{
                "code": 2002,
                "msg":  "无效的参数",
            })
            c.Abort()
            return
        }
    
        // 校验用户名与密码是否正确
        if user.Username != "whw" || user.Password != "666" {
            c.JSON(200, gin.H{
                "code": 2001,
                "msg":  "用户名或密码错误",
            })
            c.Abort()
            return
        }
    
        // 生成Token
        tokenString, _ := GenToken(user.Username)
        c.JSON(200, gin.H{
            "code": 2000,
            "msg":  "success",
            "data": gin.H{"token": tokenString, "tokenExpire": 7200},
        })
        return
    }
    
    // 4、实现校验的中间件
    // JWTAuthMiddleware 基于JWT的认证中间件
    func JWTAuthMiddleware() func(c *gin.Context) {
        return func(c *gin.Context) {
            // 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URI
            // 这里假设Token放在Header的Authorization中,并使用Bearer开头
            // 这里的具体实现方式要依据你的实际业务情况决定
            authHeader := c.Request.Header.Get("Authorization") // 获取请求头中的数据
            if authHeader == "" {
                c.JSON(http.StatusOK, gin.H{
                    "code": 2003,
                    "msg":  "请求头中auth为空",
                })
                // 不进行下面的请求处理了!
                c.Abort()
                return
            }
            // 按空格分割
            parts := strings.SplitN(authHeader, " ", 2)
            if !(len(parts) == 2 && parts[0] == "Bearer") {
                c.JSON(http.StatusOK, gin.H{
                    "code": 2004,
                    "msg":  "请求头中auth格式有误",
                })
                // 不进行下面的请求处理了!
                c.Abort()
                return
            }
            // parts[1]是获取到的tokenString,我们使用之前定义好的解析JWT的函数来解析它
            mc, err := ParseToken(parts[1])
            if err != nil {
                c.JSON(http.StatusOK, gin.H{
                    "code": 2005,
                    "msg":  "无效的Token",
                })
                // 不进行下面的请求处理了!
                c.Abort()
                return
            }
            // 将当前请求的username信息保存到请求的上下文c上
            c.Set("username", mc.Username)
            c.Next() // 后续的处理函数可以用过c.Get("username")来获取当前请求的用户信息
        }
    }
    
    // *** 开始测试
    func TestJWTAuth(t *testing.T) {
        // 默认引擎
        r := gin.Default()
    
        // 注册路由
        // 生成token的请求
        r.POST("/auth", authHandler)
        // home路由需要注册认证中间件
        r.GET("/home", JWTAuthMiddleware(), homeHandler)
    
        // 启动
        r.Run("127.0.0.1:9100")
    
    }
    
    // home路由
    func homeHandler(c *gin.Context) {
        // 获取参数
        username := c.MustGet("username").(string)
    
        // 返回响应
        c.JSON(http.StatusOK, gin.H{
            "code": 2000,
            "msg":  "success",
            "data": gin.H{"username": username},
        })
    }
    View Code

    认证过程

    启动服务后,需要首先生成token,我这里使用postman测试:

    生成token成功后,需要在auth头中加入bearer token,token的具体值就是上面生成的那个:

    ~~~

  • 相关阅读:
    【剑指offer】字符串转整数
    怎样让js不产生冲突,避免全局变量的泛滥,合理运用命名空间
    [每天一个知识点]34-职业生涯-用得着和用不着的知识
    真机iOS SDK升级后xcode不能进行真机调试 怎么办
    SPOJ 11840. Sum of Squares with Segment Tree (线段树,区间更新)
    Atitit.Gui控件and面板----web server区----- web服务器监控面板and控制台条目
    Struts2+Spring+Hibernate step by step 03 整合Spring之中的一个(在DAO层验证username和password)
    WPF中控件ListView和DataGrid典型属性介绍
    leetcode
    layer:好看的弹出窗口
  • 原文地址:https://www.cnblogs.com/paulwhw/p/14104663.html
Copyright © 2011-2022 走看看