使用hertz的keyauth中间件进行用户验证 | 青训营笔记

289 阅读2分钟

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

最近在做青训营的大项目,需要进行用户验证,于是稍微去了解了一下Hertz框架里跟认证相关的中间件。

要使用该中间件,需要导入Hertz的keyauth包。先看看该中间件的执行流程

func(c context.Context, ctx *app.RequestContext) {
   // Filter request to skip middleware
   if cfg.filterHandler != nil && cfg.filterHandler(c, ctx) {
      ctx.Next(c)
      return
   }
   // Extract and verify key
   key, err := extractor(ctx)
   if err != nil {
      cfg.errorHandler(c, ctx, err)
      return
   }
   valid, err := cfg.validator(c, ctx, key)
   if err == nil && valid {
      ctx.Set(cfg.contextKey, key)
      cfg.successHandler(c, ctx)
      return
   }
   cfg.errorHandler(c, ctx, err)
}

其中filterHandlerextractorerrorHandlervalidatorsuccessHandler都是我们可以自定义的函数。例如可以使用keyauth.New(keyauth.WithValidator(validator))的方式创建自己的中间件。

首先,该中间件判断是否需要对该请求进行认证。若filterHandler则调用之,返回值若为true则跳过认证步骤。

然后从请求中提取认证所需要的字段。可以指定从cookieheaderparamqueryform中提取,提取失败会返回ErrMissingOrMalformedAPIKey错误。

若提取失败,则调用errorHandler函数进行错误处理。默认情况下(即不使用自定义的errorHandler),若字段提取失败,返回http.StatusBadRequest,否则返回http.StatusUnauthorized

之后调用validator,刚才提取出的字段会被作为参数传入,用于判断是否认证通过。这个函数是认证的关键所在,可以使用刚才提取出的用户名和密码去数据库查询,也可以用提取出的token去redis中匹配用户id等。但是如果采用jwt认证,Hertz有专门的jwt中间件。

若认证成功,调用successHandler进行后续处理,默认什么也不做,直接调用ctx.Next

若认证失败,则调用errorHandler

如果没有什么特殊需求,那么只需要自定义需要提取的参数,以及认证函数即可,例如:

keyauth.New(
   keyauth.WithKeyLookUp("query:token", "Bearer"),
   keyauth.WithValidator(func(ctx context.Context, c *app.RequestContext, s string) (bool, error) {
      claim, err := validateToken(s)
      if err != nil {
         return false, nil
      }
      if claim.ExpiresAt < time.Now().Unix() {
         return false, nil
      }
      c.Set("uid", claim.Id)
      return true, nil
   }),
)

该中间件从到来的请求中的query获取token值,然后在validator中解析token,判断其是否过期。若未过期,则将其中的用户ID存入上下文中,以便后续调用链上的函数获取。