Go-kratos 框架商城微服务实战六
中间件-jwt鉴权
在使用的时候,遇到了一些问题,官网的信息也不是很明确,记录于次。
- 首先参考示例写法(jwt鉴权+白名单)[github.com/go-kratos/b…]
- 不难发现需要咱们处理的地方有以下几处
-
函数的白名单设置
func NewWhiteListMatcher() selector.MatchFunc { whiteList := make(map[string]struct{}) whiteList["/shop.interface.v1.ShopInterface/Login"] = struct{}{} whiteList["/shop.interface.v1.ShopInterface/Register"] = struct{}{} return func(ctx context.Context, operation string) bool { if _, ok := whiteList[operation]; ok { return false } return true } } -
NewHTTPServer的传入参数
ac *conf.Auth, 这里涉及到依赖注入的过程, 咱们先忽略掉。 -
核心部分则是中间件的使用
selector.Server( jwt.Server(func(token *jwt2.Token) (interface{}, error) { return []byte(ac.ApiKey), nil }, jwt.WithSigningMethod(jwt2.SigningMethodHS256), jwt.WithClaims(func() jwt2.Claims { return &jwt2.MapClaims{} })), ). Match(NewWhiteListMatcher()). Build(),结合 selector 和 jwt 来做白名单过滤, 这里为了忽略掉依赖注入的影响, 可以改成如下内容。
selector.Server( jwt.Server(func(token *jwt2.Token) (interface{}, error) { return []byte("testKey"), nil }, jwt.WithSigningMethod(jwt2.SigningMethodHS256), jwt.WithClaims(func() jwt2.Claims { return &jwt2.MapClaims{} })), ). Match(NewWhiteListMatcher()). Build(),
白名单处理
踩坑的地方在于白名单的设置规则, 白名单的读取是通过读取\api目录下对应的proto文件进行的。
例如:在 `/api/user/v1/user.proto中, 有如下定义
service User {
rpc CreateUser (CreateUserRequest) returns (CreateUserReply) {
option (google.api.http) = {
post: "/v1/users"
body: "*"
};
}
}
那么想对/v1/users进行白名单设置, 需要这样设置
whiteList["/api.user.v1.User/CreateUser"] = struct{}{}
// package名/接口名
下面给出完整代码
package server
import (
"context"
v1 "kratos-shop/api/helloworld/v1"
v2 "kratos-shop/api/shop/v1"
"kratos-shop/app/shop/internal/conf"
"kratos-shop/app/shop/internal/service"
"github.com/go-kratos/kratos/v2/log"
"github.com/go-kratos/kratos/v2/middleware/auth/jwt"
"github.com/go-kratos/kratos/v2/middleware/logging"
"github.com/go-kratos/kratos/v2/middleware/metadata"
"github.com/go-kratos/kratos/v2/middleware/recovery"
"github.com/go-kratos/kratos/v2/middleware/selector"
"github.com/go-kratos/kratos/v2/middleware/validate"
"github.com/go-kratos/kratos/v2/transport/http"
jwtv5 "github.com/golang-jwt/jwt/v5"
"github.com/gorilla/handlers"
)
// NewHTTPServer new an HTTP server.
func NewHTTPServer(c *conf.Server, ac *conf.Auth, s *service.ShopService, greeter *service.GreeterService, logger log.Logger) *http.Server {
var opts = []http.ServerOption{
http.Middleware(
recovery.Recovery(),
validate.Validator(),
selector.Server(
jwt.Server(func(token *jwtv5.Token) (interface{}, error) {
return []byte(ac.JwtKey), nil
}),
).Match(NewWhiteListMatcher()).Build(), // 设置白名单
metadata.Server(),
logging.Server(logger),
),
http.Filter(handlers.CORS( // 浏览器跨域
handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type", "Authorization"}),
handlers.AllowedMethods([]string{"GET", "POST", "PUT", "HEAD", "OPTIONS"}),
handlers.AllowedOrigins([]string{"*"}),
)),
}
if c.Http.Network != "" {
opts = append(opts, http.Network(c.Http.Network))
}
if c.Http.Addr != "" {
opts = append(opts, http.Address(c.Http.Addr))
}
if c.Http.Timeout != nil {
opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration()))
}
srv := http.NewServer(opts...)
v1.RegisterGreeterHTTPServer(srv, greeter)
v2.RegisterShopHTTPServer(srv, s)
return srv
}
// NewWhiteListMatcher 设置白名单,不需要 token 验证的接口
func NewWhiteListMatcher() selector.MatchFunc {
whiteList := make(map[string]struct{})
whiteList["/shop.shop.v1.Shop/Captcha"] = struct{}{}
whiteList["/shop.shop.v1.Shop/Login"] = struct{}{}
whiteList["/shop.shop.v1.Shop/Register"] = struct{}{}
return func(ctx context.Context, operation string) bool {
if _, ok := whiteList[operation]; ok {
return false
}
return true
}
}