乘风原创程序

  • golang中gin框架接入jwt使用token验证身份
  • 2021/12/9 14:53:30
  • jwt

    jwt的原理和session有点相像,其目的是为了解决rest api中无状态性

    因为rest接口,需要权限校验。但是又不能每个请求都把用户名密码传入,因此产生了这个token的方法

    流程:

    用户访问auth接口,获取token

    服务器校验用户传入的用户名密码等信息,确认无误后,产生一个token。这个token其实是类似于map的数据结构(jwt数据结构)中的key。

    准确的应该是:token中其实就保存了用户的信息,只是被加密过了。怪不得服务器重启了token还能使用,就是这个原因,因为数据就是保存在token这条长长的字符串中的。

    用户访问需要权限验证的接口,并传入token。

    服务器验证token:根据自己的token密钥判断token是否正确(是否被别人篡改),正确后才从token中解析出token中的信息。可能会把解析出的信息保存在context中

    这里使用开源的 jwt-go

    1.token 工具类

    package handler
    
    import (
     "awesomeproject/utils"
     "github.com/dgrijalva/jwt-go"
     "github.com/gin-gonic/gin"
     "time"
    )
    //用户信息类,作为生成token的参数
    type userclaims struct {
     id    string `json:"userid"`
     name  string `json:"name"`
     phone string `json:"phone"`
     //jwt-go提供的标准claim
     jwt.standardclaims
    }
    
    var (
     //自定义的token秘钥
     secret = []byte("16849841325189456f487")
     //该路由下不校验token
     noverify = []interface{}{"/login", "/ping"}
     //token有效时间(纳秒)
     effecttime = 2 * time.hour
    )
    
    // 生成token
    func generatetoken(claims *userclaims) string {
     //设置token有效期,也可不设置有效期,采用redis的方式
     //   1)将token存储在redis中,设置过期时间,token如没过期,则自动刷新redis过期时间,
     //   2)通过这种方式,可以很方便的为token续期,而且也可以实现长时间不登录的话,强制登录
     //本例只是简单采用 设置token有效期的方式,只是提供了刷新token的方法,并没有做续期处理的逻辑
     claims.expiresat = time.now().add(effecttime).unix()
     //生成token
     sign, err := jwt.newwithclaims(jwt.signingmethodhs256, claims).signedstring(secret)
     if err != nil {
      //这里因为项目接入了统一异常处理,所以使用panic并不会使程序终止,如不接入,可使用原始方式处理错误
      //接入统一异常可参考 https://blog.csdn.net/u014155085/article/details/106733391
      panic(err)
     }
     return sign
    }
    
    //验证token
    func jwtverify(c *gin.context) {
     //过滤是否验证token
     if utils.iscontainarr(noverify, c.request.requesturi) {
      return
     }
     token := c.getheader("token")
     if token == "" {
      panic("token not exist !")
     }
     //验证token,并存储在请求中
     c.set("user", parsetoken(token))
    }
    
    // 解析token
    func parsetoken(tokenstring string) *userclaims {
     //解析token
     token, err := jwt.parsewithclaims(tokenstring, &userclaims{}, func(token *jwt.token) (interface{}, error) {
      return secret, nil
     })
     if err != nil {
      panic(err)
     }
     claims, ok := token.claims.(*userclaims)
     if !ok {
      panic("token is valid")
     }
     return claims
    }
    
    // 更新token
    func refresh(tokenstring string) string {
     jwt.timefunc = func() time.time {
      return time.unix(0, 0)
     }
     token, err := jwt.parsewithclaims(tokenstring, &userclaims{}, func(token *jwt.token) (interface{}, error) {
      return secret, nil
     })
     if err != nil {
      panic(err)
     }
     claims, ok := token.claims.(*userclaims)
     if !ok {
      panic("token is valid")
     }
     jwt.timefunc = time.now
     claims.standardclaims.expiresat = time.now().add(2 * time.hour).unix()
     return generatetoken(claims)
    }

    2. 使用该中间件

    func main() {
     router := gin.default()
     router.use(handler.jwtverify)
    
     router.get("/ping", controller.ping)
     router.get("/login", controller.login)
     router.get("/userinfo", controller.userinfo)
    
     router.run(":8888") // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
    
    }

    3. controller部分代码

    package controller
    
    import (
     "awesomeproject/handler"
     "awesomeproject/utils"
     "github.com/dgrijalva/jwt-go"
     "github.com/gin-gonic/gin"
     "net/http"
    )
    
    func ping(c *gin.context) {
     c.json(http.statusok, utils.resultt("this is ping"))
    }
    
    func login(c *gin.context) {
     c.json(http.statusok, utils.resultt(gin.h{
      "token": handler.generatetoken(&handler.userclaims{
       id:             "001",
       name:           "张三",
       phone:          "189***0023",
       standardclaims: jwt.standardclaims{},
      }),
     }))
    
    }
    
    func userinfo(c *gin.context) {
     user, _ := c.get("user")
     claims := user.(*handler.userclaims)
     c.json(http.statusok, utils.resultt(claims.phone))
    }

    到此这篇关于golang中gin框架接入jwt使用token验证身份的文章就介绍到这了,更多相关gin jwt token验证身份内容请搜索本教程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持本教程网!