mirror of
https://github.com/eolinker/apinto
synced 2026-04-22 16:07:04 +08:00
finish params check v2
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user