Hertz中的JWT中间件使用 | 青训营笔记

310 阅读2分钟

这是我参与「第五届青训营 」笔记创作活动的第11天。

之前发文介绍了Hertz中的Keyauth认证方法,这种办法限制较少,但是如果用JWT认证的话,需要自己实现token的签发与解析。现在来介绍一下JWT中间件,顾名思义,这就是专门用来实现JWT认证的,自带了签发与解析功能,但是会存在一些限制。

先来看一下中间件的实现流程:

func (mw *HertzJWTMiddleware) middlewareImpl(ctx context.Context, c *app.RequestContext) {
   claims, err := mw.GetClaimsFromJWT(ctx, c)
   if err != nil {
      mw.unauthorized(ctx, c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, ctx, c))
      return
   }

   switch v := claims["exp"].(type) {
//判断是否过期
   }

   c.Set("JWT_PAYLOAD", claims)
   identity := mw.IdentityHandler(ctx, c)

   if identity != nil {
      c.Set(mw.IdentityKey, identity)
   }

   if !mw.Authorizator(identity, ctx, c) {
      mw.unauthorized(ctx, c, http.StatusForbidden, mw.HTTPStatusMessageFunc(ErrForbidden, ctx, c))
      return
   }

   c.Next(ctx)
}

首先,中间件会从用户请求中提取Claim,若成功提取则判断其是否过期。然后将Claim存入key为"JWT_PAYLOAD"的上下文中,将身份信息(用户自定义)存入key为mw.IdentityKey的上下文中,便于之后的处理函数获取。最后中间件根据用户自定义的身份验证函数验证用户信息,若通过则执行下一个处理函数。

相比keyauth来说,需要用户自己编写的部分少了很多:

mid, _ := jwt.New(&jwt.HertzJWTMiddleware{
   Realm:       "douyin",
   Key:         []byte(key),
   IdentityKey: "uid",
   PayloadFunc: func(data interface{}) jwt.MapClaims {
      return jwt.MapClaims{"uid": strconv.FormatInt(data.(*domain.TokenClaims).Uid, 10)}
   },
   IdentityHandler: func(ctx context.Context, c *app.RequestContext) interface{} {
      claims := jwt.ExtractClaims(ctx, c)
      i, _ := strconv.ParseInt(claims["uid"].(string), 10, 64)
      return i
   },
   TokenLookup: "form:token, query: token",
   Unauthorized: func(ctx context.Context, c *app.RequestContext, code int, message string) {
      c.JSON(code, map[string]interface{}{
         "code":    code,
         "message": message,
      })
   },
})
  • Key是用于JWT加密的密钥。
  • IdentityKey是把Identity存入上下文所用的key,即,之后的处理函数中可以用ctx.get(IdentityKey)的方式来获取之。
  • PayloadFunc是存储在claim中的信息,此处存储了用户的uid。
  • IdentityHandler用于从解密的claim中提取用于验证所需的Identity,此处提取了用户的uid。
  • TokenLookup指从哪里获取token,此处从form和query的token字段中获取。
  • Unauthorized指要是验证不通过后要做什么。

还有一个问题就是,在登录函数里要怎么把token放进响应头中。JWT中间件为我们提供了一个登录函数模板,但是用别人的东西毕竟不太顺手。实际上只需要在自己的登录函数里调用中间件的TokenGenerator(claims)方法即可拿到token。