当前位置: 移动技术网 > IT编程>脚本编程>Go语言 > golang jwt-go的使用

golang jwt-go的使用

2020年03月14日  | 移动技术网IT编程  | 我要评论

jwt(json web token)

jwt

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

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

流程:

https://blog.wangjunfeng.com/post/golang-jwt/#3-%e7%ad%be%e5%90%8d-signature

  1. 用户访问auth接口,获取token

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

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

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

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

使用步骤

  1. 下载依赖包

    go get -u github.com/dgrijalva/jwt-go

  2. 编写jwt工具包,用户创建和检查token

    分为几个部分:

    1. 指定加密密钥
    2. 指定被保存在token中的实体对象,claims 结构体。需要内嵌jwt.standardclaims。这个结构体是用来保存信息的。
    3. 根据数据产生token:根据传入的信息,组装成一个claims结构体对象,再从对象中获取token
    4. 根据token解析数据:解析出token所对应的interface{},再使用断言解析出claims对象,取数据
    / 指定加密密钥
    var jwtsecret=[]byte(setting.jwtsecret)
    
    //claim是一些实体(通常指的用户)的状态和额外的元数据
    type claims struct{
     username string `json:"username"`
     password string `json:"password"`
     jwt.standardclaims
    }
    
    // 根据用户的用户名和密码产生token
    func generatetoken(username ,password string)(string,error){
     //设置token有效时间
     nowtime:=time.now()
     expiretime:=nowtime.add(3*time.hour)
    
     claims:=claims{
         username:       username,
         password:       password,
         standardclaims: jwt.standardclaims{
                // 过期时间
             expiresat:expiretime.unix(),
             // 指定token发行人
             issuer:"gin-blog",
         },
     }
    
     tokenclaims:=jwt.newwithclaims(jwt.signingmethodhs256,claims)
     //该方法内部生成签名字符串,再用于获取完整、已签名的token
     token,err:=tokenclaims.signedstring(jwtsecret)
     return token,err
    }
    
    // 根据传入的token值获取到claims对象信息,(进而获取其中的用户名和密码)
    func parsetoken(token string)(*claims,error){
    
     //用于解析鉴权的声明,方法内部主要是具体的解码和校验的过程,最终返回*token
     tokenclaims, err := jwt.parsewithclaims(token, &claims{}, func(token *jwt.token) (interface{}, error) {
         return jwtsecret, nil
     })
    
     if tokenclaims!=nil{
         // 从tokenclaims中获取到claims对象,并使用断言,将该对象转换为我们自己定义的claims
         // 要传入指针,项目中结构体都是用指针传递,节省空间。
         if claims,ok:=tokenclaims.claims.(*claims);ok&&tokenclaims.valid{
             return claims,nil
         }
     }
     return nil,err
    
    }
  3. 编写路由,返回token

    (需要做用户参数校验与错误处理)

    1. 用户参数校验
    type auth struct{
     username string `valid:"required;maxsize(50)"`
     password string `valid:"required;maxsize(50)"`
    }
    
    func getauth(c *gin.context){
     username:=c.query("username")
     password:=c.query("password")
    
     valid:=validation.validation{}
     a:=auth{
         username: username,
         password: password,
     }
    
    
     // 与之前的对每一个数据分开验证不同,此处在auth对象中通过定义标签valid
     // 一次性校验对象中的所有字段信息
     ok,_:=valid.valid(&a)
    
    
     //创建返回信息
     data:=make(map[string]interface{})
     code:=e.invalid_params
     /*
     根据用户名密码获取token 判断流程:
     1. 先判断用户名密码是否存在
     */
     if ok{
         isexist:=models.checkauth(username,password)
         if isexist{
             token,err:=util.generatetoken(username,password)
             if err!=nil{
                 code=e.error_auth_token
             }else{
                 data["token"]=token
                 code=e.success
             }
         }else{
             code=e.error_auth
         }
     }else{
         //如果数据验证失败,则打印结果
         for _,err:=range valid.errors{
             log.println(err.key,err.message)
         }
     }
    
     c.json(http.statusok,util.returndata(code,e.getmsg(code),data))
    }
  4. 编写中间件,校验token字符串

    func jwy()gin.handlerfunc{
     return func(c *gin.context){
         var  code int
         var data interface{}
    
         code=e.success
         token:=c.query("token")
         if token==""{
             code=e.error_auth_no_tokrn
         }else{
             claims,err:=util.parsetoken(token)
             if err!=nil{
                 code=e.error_auth_check_token_fail
             }else if time.now().unix()>claims.expiresat{
                 code=e.error_auth_check_token_timeout
             }
         }
    
         //如果token验证不通过,直接终止程序,c.abort()
         if code!=e.success{
             // 返回错误信息
             c.json(http.statusunauthorized,util.returndata(code,e.getmsg(code),data))
             //终止程序
             c.abort()
             return
         }
         c.next()
     }
    }

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网