wx

关注公众号领取Go学习资料

wx

洋葱小店

03:开发自定义中间件


Kratos 内置了一系列的 middleware(中间件)用于处理 logging、 metrics 等通用场景。您也可以通过实现 Middleware 接口,开发自定义 middleware,进行通用的业务处理,比如用户登录鉴权等。

1、Kratos 中间件生效顺序:

一个请求进入时的处理顺序为 Middleware 注册的顺序,而响应返回的处理顺序为注册顺序的倒序

         ┌───────────────────┐
         │MIDDLEWARE 1       
          ┌────────────────┐│
          │MIDDLEWARE 2    ││
           ┌─────────────┐││
           │MIDDLEWARE 3 │││
            ┌─────────┐ │││
REQUEST       YOUR    │││  RESPONSE
   ──────┼─┼─┼─▷ HANDLER ○─┼┼┼───▷
            └─────────┘ │││
           └─────────────┘││
          └────────────────┘│
         └───────────────────┘

自定义中间件

一、实现一个Token验证中间件,需要实现接口:Middleware;下面实现通过JWT Token 验证登录状态的中间件; 1、使用 tr, ok := transport.FromServerContext(ctx) 获得 Transporter 实例 2、从 Transporter 对象获取 Header中的 token,并进行验证; 3、通过 selector.Server 设置验证白名单; 最终实现代码如下:

package server

import (
	"context"
	"strings"

	"github.com/go-kratos/kratos/v2/middleware"
	"github.com/go-kratos/kratos/v2/middleware/auth/jwt"
	"github.com/go-kratos/kratos/v2/middleware/selector"
	"github.com/go-kratos/kratos/v2/transport"
	v1 "sys_api/api/gen/user/v1"
	"sys_api/internal/conf"
	"sys_api/pkg/app"
)

var ERROR_UNAUTH = v1.ErrorNotLoggedIn("认证失败")

func authMiddleware(conf *conf.Data_Jwt) middleware.Middleware {

	return selector.Server(
		func(handler middleware.Handler) middleware.Handler {
			return func(ctx context.Context, req interface{}) (reply interface{}, err error) {
				if tr, ok := transport.FromServerContext(ctx); ok {
					token := tr.RequestHeader().Get("Authorization")
					token = strings.Replace(token, "Bearer", "", 1)
					if token == "" {
						err = ERROR_UNAUTH
						return
					}
					claims, parseErr := app.ParseToken(conf, token)
					if parseErr != nil || claims == nil {
						return nil, ERROR_UNAUTH.WithCause(parseErr)
					}
					nctx := jwt.NewContext(ctx, claims)
					reply, err = handler(nctx, req)
					return
				}
				err = jwt.ErrMissingJwtToken
				return
			}
		},
	).Match(NewWhiteListMatcher()).Build()
}

// NewWhiteListMatcher 创建jwt白名单
func NewWhiteListMatcher() selector.MatchFunc {
	whiteList := make(map[string]bool)
	//忽略登录验证接口
	whiteList[v1.UserService_Login_FullMethodName] = true

	return func(ctx context.Context, operation string) bool {
		if _, ok := whiteList[operation]; ok {
			return false
		}
		return true
	}
}

二、实现一个参数签名验证中间件:

if tr, ok := transport.FromServerContext(ctx); ok {	
    if ht, ok := tr.(*http.Transport); ok {
        httpReq := ht.Request() // 返回 *http.Request 
        //TODO 通过 *http.Request 获取到参训进行签名验证
    }
    reply, err = handler(ctx, req)
    return
}

使用中间件

在 NewGRPCServer 和 NewHTTPServer 中通过 ServerOption 进行注册。

var opts = []http.ServerOption{
		http.Middleware(
			tracing.Server(),
			logging.Server(logger),
			validate.Validator(),
			authMiddleware(jwtConf),
			recovery.Recovery(),
		),
	}
如有疑问关注公众号给我留言
wx

关注公众号领取Go学习资料

wx

洋葱小店

©2017-2023 鲁ICP备17023316号-1 Powered by Hugo