diff --git a/app/apinto/plugin.go b/app/apinto/plugin.go index a1f2a98d..2d996aa4 100644 --- a/app/apinto/plugin.go +++ b/app/apinto/plugin.go @@ -16,6 +16,7 @@ import ( js_inject "github.com/eolinker/apinto/drivers/plugins/js-inject" "github.com/eolinker/apinto/drivers/plugins/oauth2" params_check "github.com/eolinker/apinto/drivers/plugins/params-check" + params_check_v2 "github.com/eolinker/apinto/drivers/plugins/params-check-v2" "github.com/eolinker/apinto/drivers/plugins/prometheus" request_file_parse "github.com/eolinker/apinto/drivers/plugins/request-file-parse" request_interception "github.com/eolinker/apinto/drivers/plugins/request-interception" @@ -82,7 +83,7 @@ func pluginRegister(extenderRegister eosc.IExtenderDriverRegister) { proxy_rewrite_v2.Register(extenderRegister) http_mocking.Register(extenderRegister) params_check.Register(extenderRegister) - //params_check_v2.Register(extenderRegister) + params_check_v2.Register(extenderRegister) data_transform.Register(extenderRegister) request_interception.Register(extenderRegister) request_file_parse.Register(extenderRegister) diff --git a/drivers/plugins/params-check-v2/check.go b/drivers/plugins/params-check-v2/check.go index 28cd38d1..59c3e198 100644 --- a/drivers/plugins/params-check-v2/check.go +++ b/drivers/plugins/params-check-v2/check.go @@ -19,7 +19,7 @@ var ( ) type IParamChecker interface { - Check(logic string, header http_service.IHeaderReader, query http_service.IQueryReader, body interface{}, fn bodyCheckerFunc) bool + Check(header http_service.IHeaderReader, query http_service.IQueryReader, body interface{}, fn bodyCheckerFunc) bool } type headerChecker struct { @@ -27,7 +27,7 @@ type headerChecker struct { checker checker.Checker } -func (h *headerChecker) Check(logic string, header http_service.IHeaderReader, query http_service.IQueryReader, body interface{}, fn bodyCheckerFunc) bool { +func (h *headerChecker) Check(header http_service.IHeaderReader, query http_service.IQueryReader, body interface{}, fn bodyCheckerFunc) bool { v := header.GetHeader(h.name) match := h.checker.Check(v, true) if !match { @@ -49,7 +49,7 @@ type queryChecker struct { checker checker.Checker } -func (q *queryChecker) Check(logic string, header http_service.IHeaderReader, query http_service.IQueryReader, body interface{}, fn bodyCheckerFunc) bool { +func (q *queryChecker) Check(header http_service.IHeaderReader, query http_service.IQueryReader, body interface{}, fn bodyCheckerFunc) bool { v := query.GetQuery(q.name) match := q.checker.Check(v, true) if !match { @@ -91,7 +91,7 @@ func newBodyChecker(name string, matchText string, matchMode string) (*bodyCheck }, nil } -func (b *bodyChecker) Check(logic string, header http_service.IHeaderReader, query http_service.IQueryReader, body interface{}, fn bodyCheckerFunc) bool { +func (b *bodyChecker) Check(header http_service.IHeaderReader, query http_service.IQueryReader, body interface{}, fn bodyCheckerFunc) bool { return fn(body, b) == nil } @@ -103,7 +103,10 @@ type paramChecker struct { checker IParamChecker } -func genParamChecker(param *Param) (IParamChecker, error) { +func genParamChecker(param *SubParam) (IParamChecker, error) { + if param == nil { + return nil, nil + } if param.Position == "" { return nil, nil } @@ -130,17 +133,22 @@ func genParamChecker(param *Param) (IParamChecker, error) { } func newParamChecker(param *Param) (*paramChecker, error) { - ck, err := genParamChecker(param) + ck, err := genParamChecker(&SubParam{ + Name: param.Name, + Position: param.Position, + MatchText: param.MatchText, + MatchMode: param.MatchMode, + }) if err != nil { return nil, err } cks := make([]IParamChecker, 0, len(param.Params)) for _, p := range param.Params { - ck, err := genParamChecker(p) + c, err := genParamChecker(p) if err != nil { return nil, err } - cks = append(cks, ck) + cks = append(cks, c) } return ¶mChecker{ @@ -150,21 +158,22 @@ func newParamChecker(param *Param) (*paramChecker, error) { }, nil } -func (c *paramChecker) Check(logic string, header http_service.IHeaderReader, query http_service.IQueryReader, body interface{}, fn bodyCheckerFunc) bool { - success := false +func (c *paramChecker) Check(header http_service.IHeaderReader, query http_service.IQueryReader, body interface{}, fn bodyCheckerFunc) bool { + success := true for _, ck := range c.checkers { if ck == nil { continue } - ok := ck.Check(c.logic, header, query, body, fn) + ok := ck.Check(header, query, body, fn) if !ok { - if logic == logicAnd { + if c.logic == logicAnd { return false } + success = false continue } else { success = true - if logic == logicOr { + if c.logic == logicOr { break } } @@ -175,7 +184,7 @@ func (c *paramChecker) Check(logic string, header http_service.IHeaderReader, qu if c.checker == nil { return true } - return c.checker.Check(c.logic, header, query, body, fn) + return c.checker.Check(header, query, body, fn) } func formChecker(body interface{}, ck *bodyChecker) error { diff --git a/drivers/plugins/params-check-v2/check_test.go b/drivers/plugins/params-check-v2/check_test.go index 87f733f8..b866bc59 100644 --- a/drivers/plugins/params-check-v2/check_test.go +++ b/drivers/plugins/params-check-v2/check_test.go @@ -59,7 +59,7 @@ func TestParamCheckLogic(t *testing.T) { name: "And logic", param: &Param{ Logic: logicAnd, - Params: []*Param{ + Params: []*SubParam{ { Position: positionHeader, Name: "X-Test-Header", @@ -85,7 +85,7 @@ func TestParamCheckLogic(t *testing.T) { name: "Or logic", param: &Param{ Logic: logicOr, - Params: []*Param{ + Params: []*SubParam{ { Position: positionHeader, Name: "X-Test-Header", @@ -111,7 +111,7 @@ func TestParamCheckLogic(t *testing.T) { name: "And logic (fail case)", param: &Param{ Logic: logicAnd, - Params: []*Param{ + Params: []*SubParam{ { Position: positionHeader, Name: "X-Test-Header", @@ -137,7 +137,7 @@ func TestParamCheckLogic(t *testing.T) { name: "Or logic (fail case)", param: &Param{ Logic: logicOr, - Params: []*Param{ + Params: []*SubParam{ { Position: positionHeader, Name: "X-Test-Header", @@ -164,7 +164,7 @@ func TestParamCheckLogic(t *testing.T) { ck, err := newParamChecker(tt.param) assert.NoError(t, err) assert.NotNil(t, ck) - assert.Equal(t, tt.expected, ck.Check(tt.param.Logic, &MockHeaderReader{headers: tt.header}, &MockQueryReader{queries: tt.query}, nil, nil)) + assert.Equal(t, tt.expected, ck.Check(&MockHeaderReader{headers: tt.header}, &MockQueryReader{queries: tt.query}, nil, nil)) }) } } @@ -206,7 +206,7 @@ func TestParamCheck(t *testing.T) { { name: "Body array match any", param: &Param{ - Params: []*Param{ + Params: []*SubParam{ { Position: positionBody, Name: "search[*].val", @@ -228,7 +228,7 @@ func TestParamCheck(t *testing.T) { { name: "Header match", param: &Param{ - Params: []*Param{ + Params: []*SubParam{ { Position: positionHeader, Name: "X-Test-Header", @@ -246,7 +246,7 @@ func TestParamCheck(t *testing.T) { { name: "Query match", param: &Param{ - Params: []*Param{ + Params: []*SubParam{ { Position: positionQuery, Name: "query-param", @@ -264,7 +264,7 @@ func TestParamCheck(t *testing.T) { { name: "Body array match all (fail case)", param: &Param{ - Params: []*Param{ + Params: []*SubParam{ { Position: positionBody, Name: "search[*].val", @@ -301,7 +301,7 @@ func TestParamCheck(t *testing.T) { queryReader := &MockQueryReader{queries: test.query} // 执行校验 - ok := ck.Check(test.param.Logic, headerReader, queryReader, body, jsonChecker) + ok := ck.Check(headerReader, queryReader, body, jsonChecker) // 检查结果 if ok != test.expected { diff --git a/drivers/plugins/params-check-v2/config.go b/drivers/plugins/params-check-v2/config.go index 9c404d7c..9657d979 100644 --- a/drivers/plugins/params-check-v2/config.go +++ b/drivers/plugins/params-check-v2/config.go @@ -6,40 +6,82 @@ import ( "github.com/eolinker/apinto/checker" ) -type Config Param - -type Param struct { - Name string `json:"name" label:"参数名"` - Position string `json:"position" label:"参数位置" enum:"query,header,body"` - MatchText string `json:"match_text" label:"匹配文本"` - MatchMode string `json:"match_mode" label:"匹配模式" enum:"any,all"` - Logic string `json:"logic" label:"逻辑" enum:"and,or"` - Params []*Param `json:"params" label:"参数列表"` +type Config struct { + Logic string `json:"logic" label:"逻辑" enum:"and,or"` + Params []*Param `json:"params" label:"参数列表"` } -func checkParam(conf *Param) error { - if conf.Name == "" && len(conf.Params) == 0 { +type Param struct { + Name string `json:"name" label:"参数名"` + Position string `json:"position" label:"参数位置" enum:"query,header,body"` + MatchText string `json:"match_text" label:"匹配文本"` + MatchMode string `json:"match_mode" label:"匹配模式" enum:"any,all"` + Logic string `json:"logic" label:"逻辑" enum:"and,or"` + Params []*SubParam `json:"params" label:"参数列表"` +} + +func (p *Param) check() error { + if p.Name == "" && len(p.Params) == 0 { return fmt.Errorf("name is empty") } - switch conf.Position { + switch p.Position { case positionQuery, positionHeader, positionBody, "": default: return fmt.Errorf("position is error") } - switch conf.MatchMode { + switch p.MatchMode { case checker.JsonArrayMatchAll, checker.JsonArrayMatchAny: default: - conf.MatchMode = checker.JsonArrayMatchAll + p.MatchMode = checker.JsonArrayMatchAll } - switch conf.Logic { + + switch p.Logic { case logicAnd, logicOr: default: - conf.Logic = logicAnd + p.Logic = logicAnd } - for _, p := range conf.Params { - if err := checkParam(p); err != nil { + for _, sub := range p.Params { + err := sub.check() + if err != nil { return err } } return nil } + +type SubParam struct { + Name string `json:"name" label:"参数名"` + Position string `json:"position" label:"参数位置" enum:"query,header,body"` + MatchText string `json:"match_text" label:"匹配文本"` + MatchMode string `json:"match_mode" label:"匹配模式" enum:"any,all"` +} + +func (p *SubParam) check() error { + if p.Name == "" { + return fmt.Errorf("name is empty") + } + switch p.Position { + case positionQuery, positionHeader, positionBody: + default: + return fmt.Errorf("position is error") + } + switch p.MatchMode { + case checker.JsonArrayMatchAll, checker.JsonArrayMatchAny: + default: + p.MatchMode = checker.JsonArrayMatchAll + } + return nil +} + +func checkParam(conf *Config) error { + for _, p := range conf.Params { + err := p.check() + if err != nil { + return err + } + } + if conf.Logic == "" { + conf.Logic = logicAnd + } + return nil +} diff --git a/drivers/plugins/params-check-v2/executor.go b/drivers/plugins/params-check-v2/executor.go index 1bbe4dcb..062f400b 100644 --- a/drivers/plugins/params-check-v2/executor.go +++ b/drivers/plugins/params-check-v2/executor.go @@ -23,7 +23,7 @@ var _ eosc.IWorker = (*executor)(nil) type executor struct { drivers.WorkerBase logic string - ck IParamChecker + cks []IParamChecker } func (e *executor) DoFilter(ctx eocontext.EoContext, next eocontext.IChain) (err error) { @@ -33,7 +33,8 @@ func (e *executor) DoFilter(ctx eocontext.EoContext, next eocontext.IChain) (err var errParamCheck = "Can not find the %s param \"%s\" or the \"%s\" is illegal" func (e *executor) DoHttpFilter(ctx http_service.IHttpContext, next eocontext.IChain) (err error) { - if e.ck != nil { + if e.cks != nil { + cks := e.cks headerReader := ctx.Request().Header() queryReader := ctx.Request().URI() var body interface{} @@ -54,8 +55,25 @@ func (e *executor) DoHttpFilter(ctx http_service.IHttpContext, next eocontext.IC fn = jsonChecker } - ok := e.ck.Check(e.logic, headerReader, queryReader, body, fn) - if !ok { + success := true + for _, ck := range cks { + ok := ck.Check(headerReader, queryReader, body, fn) + if !ok { + if e.logic == logicAnd { + ctx.Response().SetStatus(401, "401") + ctx.Response().SetBody([]byte("param check failed")) + return err + } + success = false + continue + } else { + success = true + if e.logic == logicOr { + break + } + } + } + if !success { ctx.Response().SetStatus(401, "401") ctx.Response().SetBody([]byte("param check failed")) return err @@ -69,7 +87,7 @@ func (e *executor) DoHttpFilter(ctx http_service.IHttpContext, next eocontext.IC } func (e *executor) Destroy() { - e.ck = nil + e.cks = nil return } diff --git a/drivers/plugins/params-check-v2/factory.go b/drivers/plugins/params-check-v2/factory.go index e6c86903..1ac2fcef 100644 --- a/drivers/plugins/params-check-v2/factory.go +++ b/drivers/plugins/params-check-v2/factory.go @@ -3,6 +3,7 @@ package params_check_v2 import ( "github.com/eolinker/apinto/drivers" "github.com/eolinker/eosc" + "github.com/eolinker/eosc/log" ) const ( @@ -10,28 +11,33 @@ const ( ) func Register(register eosc.IExtenderDriverRegister) { + log.Debug("register params_check_v2 is ", Name) register.RegisterExtenderDriver(Name, NewFactory()) } func NewFactory() eosc.IExtenderDriverFactory { + return drivers.NewFactory[Config](Create) } func Create(id, name string, conf *Config, workers map[eosc.RequireId]eosc.IWorker) (eosc.IWorker, error) { - cfg := (*Param)(conf) - err := checkParam(cfg) + err := checkParam(conf) if err != nil { return nil, err } - ck, err := newParamChecker(cfg) - if err != nil { - return nil, err + cks := make([]IParamChecker, 0, len(conf.Params)) + for _, p := range conf.Params { + ck, err := newParamChecker(p) + if err != nil { + return nil, err + } + cks = append(cks, ck) } return &executor{ WorkerBase: drivers.Worker(id, name), - ck: ck, - logic: cfg.Logic, + cks: cks, + logic: conf.Logic, }, nil } diff --git a/go.mod b/go.mod index 9387c457..19343abf 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/lestrrat-go/jwx v1.2.28 github.com/nacos-group/nacos-sdk-go/v2 v2.2.3 github.com/nsqio/go-nsq v1.1.0 - github.com/ohler55/ojg v1.12.9 + github.com/ohler55/ojg v1.25.1 github.com/pkg/sftp v1.13.4 github.com/polarismesh/polaris-go v1.1.0 github.com/redis/go-redis/v9 v9.7.0 diff --git a/router/http-router/append.go b/router/http-router/append.go index 87b29e7c..71db97d1 100644 --- a/router/http-router/append.go +++ b/router/http-router/append.go @@ -161,5 +161,5 @@ func (b *BodyChecker) MatchCheck(req interface{}) bool { } func (b *BodyChecker) Weight() int { - return int(checker.CheckTypeAll-b.Checker.CheckType()) * len(b.Checker.Value()) + return int(checker.CheckTypeAll-b.Checker.CheckType()) * 50 * len(b.Checker.Value()) } diff --git a/router/http-router/matcher.go b/router/http-router/matcher.go index 468b714c..3d14752e 100644 --- a/router/http-router/matcher.go +++ b/router/http-router/matcher.go @@ -177,7 +177,7 @@ func (as AppendMatchers) Len() int { } func (as AppendMatchers) Less(i, j int) bool { - return as[i].checkers.Weight() < as[j].checkers.Weight() + return as[i].checkers.Weight() > as[j].checkers.Weight() } func (as AppendMatchers) Swap(i, j int) {