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}, }) }
认证过程
启动服务后,需要首先生成token,我这里使用postman测试:
生成token成功后,需要在auth头中加入bearer token,token的具体值就是上面生成的那个:
~~~