go install gitee.com/pengdacn/protoc-gen-go-kratos-selector@latest
-
定义handler
-
创建定义handler的protobuf文件,如下
// file: /api/middleware.proto syntax = "proto3"; package api.middleware.v1; option go_package = "api/middleware/v1;v1"; import "selector/selector.proto"; option (selector.defined) = { name: "middleware" handlers: [ { // 定义这个handle的名称,必须是唯一的,且符合golang变量命名规范 id: "jwt" // 指定优先级,1优先级最高,2其次,以此类推,若优先级别相同,则按照字符串的比较规则,比较id // property不能小于0 property: 1 }, { id: "privilege" property: 2 } ] };
-
在需要使用选择器的地方引用
middleware.proto
中定义的id,如下// file: /api/user.proto syntax = "proto3"; package api.user.v1; option go_package = "api/user/v1;v1"; import "selector/selector.proto"; import "google/api/annotations.proto"; import "google/protobuf/empty.proto"; service User { option (selector.select) = { // 代表使用的定义handler的proto文件位置,必填 use: "api/middleware.proto" verbs: [ { // verbs中的id必须是在use的proto中定义的,若没有定义,生成则会报错 id: "jwt" // 通过select语法和在方法中定义的tag去选择在这个service中匹配的方法 select: "!no-jwt" }, { id: "privilege" select: "!no-privilege" } ] }; rpc Add(google.protobuf.Empty) returns(google.protobuf.Empty) { option (google.api.http) = { post: "/api/v1/user" body: "*" }; } rpc Update(google.protobuf.Empty) returns(google.protobuf.Empty) { option (google.api.http) = { put: "/api/v1/user/{id}" body: "*" }; } rpc Remove(google.protobuf.Empty) returns(google.protobuf.Empty) { option (google.api.http) = { delete: "/api/v1/user/{id}" }; } rpc List(google.protobuf.Empty) returns(google.protobuf.Empty) { option (google.api.http) = { get: "/api/v1/users" }; } rpc Login(google.protobuf.Empty) returns(google.protobuf.Empty) { option (google.api.http) = { get: "/api/v1/users" }; option (selector.tag) = { name: "no-jwt" additional: [ "no-privilege" ] }; } rpc GetSelf(google.protobuf.Empty) returns(google.protobuf.Empty) { option (google.api.http) = { get: "/api/v1/user/self" }; option (selector.tag) = { name: "no-privilege" }; } }
在这个示例文件中,id为
jwt
的选择器会选择除了Login
方法外的其他所有方法,id为privilege
的会选择除了Login
、GetSelf
外的所有方法 -
使用
protoc
生成选择器代码protoc --proto_path=. \ --proto_path=./third_party \ --proto_path=./example \ --go_out=paths=source_relative:. \ --go-kratos-selector_out=paths=source_relative:. \ ./example/api/middleware.proto ./example/api/user.proto
--go-kratos-selector_out=paths=source_relative:. \
就是生产选择器插件位置生成后代码如下
// file: /api/middleware_selector.pb.go // Code generated by proto-gen-go-kratos-selector. DO NOT EDIT. // versions: // proto-gen-go-kratos-selector v1.0 // url: // https://gitee.com/pengdacn/protoc-gen-go-kratos-selector package v1 import ( context "context" middleware "github.com/go-kratos/kratos/v2/middleware" selector "github.com/go-kratos/kratos/v2/middleware/selector" ) type standardSelectorMiddleware struct { id_jwt map[string]struct{} middlewares_jwt []middleware.Middleware id_privilege map[string]struct{} middlewares_privilege []middleware.Middleware } type SelectorMiddleware interface { Build() middleware.Middleware Add_jwt(mlds ...middleware.Middleware) Add_privilege(mlds ...middleware.Middleware) } var ( Selector_Jwt = make(map[string]struct{}) Selector_Privilege = make(map[string]struct{}) _ SelectorMiddleware = (*standardSelectorMiddleware)(nil) ) func init() { Selector_Jwt[`/api.user.v1.User/Add`] = struct{}{} Selector_Jwt[`/api.user.v1.User/GetSelf`] = struct{}{} Selector_Jwt[`/api.user.v1.User/List`] = struct{}{} Selector_Jwt[`/api.user.v1.User/Remove`] = struct{}{} Selector_Jwt[`/api.user.v1.User/Update`] = struct{}{} Selector_Privilege[`/api.user.v1.User/Add`] = struct{}{} Selector_Privilege[`/api.user.v1.User/List`] = struct{}{} Selector_Privilege[`/api.user.v1.User/Remove`] = struct{}{} Selector_Privilege[`/api.user.v1.User/Update`] = struct{}{} } func NewSelectorMiddleware() SelectorMiddleware { return &standardSelectorMiddleware{ id_jwt: Selector_Jwt, id_privilege: Selector_Privilege, } } func (s *standardSelectorMiddleware) Build() middleware.Middleware { var selectors []middleware.Middleware selectors = append( selectors, selector.Server( middleware.Chain(s.middlewares_jwt...), ). Match(s.match_jwt()). Build(), ) selectors = append( selectors, selector.Server( middleware.Chain(s.middlewares_privilege...), ). Match(s.match_privilege()). Build(), ) return middleware.Chain(selectors...) } func (s *standardSelectorMiddleware) Add_jwt(mlds ...middleware.Middleware) { if len(mlds) != 0 { s.middlewares_jwt = append(s.middlewares_jwt, mlds...) } } func (s *standardSelectorMiddleware) match_jwt() selector.MatchFunc { return func(ctx context.Context, operation string) bool { _, ok := Selector_Jwt[operation] return ok } } func (s *standardSelectorMiddleware) Add_privilege(mlds ...middleware.Middleware) { if len(mlds) != 0 { s.middlewares_privilege = append(s.middlewares_privilege, mlds...) } } func (s *standardSelectorMiddleware) match_privilege() selector.MatchFunc { return func(ctx context.Context, operation string) bool { _, ok := Selector_Privilege[operation] return ok } }
-
在项目中使用
-
通过
v1.NewSelectorMiddleware
创建一个v1.SelectorMiddleware
对象 -
添加中间键到选择其中
-
构建对象为
kratos
的中间件,并在http.Server
或grpc.Server
中使用
http
示例如下func NewHTTPServer(u *user.Server) http.Server { // 1.创建selector对象 selectors := v1.NewSelectorMiddleware() // 2.将需要的中间件添加到handle中 selectors.Add_jwt(newAuthJwt()) selectors.Add_privilege(newAuthPrivilege()) // 3. 构建中间件对象 selectorMiddleware := selectors.Build() // 4. 使用 ... }
-
-
-
完全匹配
若有方法,
A
、B
func A tags: [a,b,c,d] func B tags: [e,a,f,g]
选择器
selector S1 select: a selector S2 select: g
则选择器
S1
匹配A
、B
,选择器S2
匹配B
-
不能等于匹配
语法:
!
+tag
,如:!a
,表示匹配除了a
tag外的所有方法,甚至方法没有tag
也会匹配 -
全部匹配
固定格式:
$any
,匹配所有方法,甚至方法没有tag
也会匹配