diff --git a/app/apinto/profession.go b/app/apinto/profession.go index 83d6ad26..c8586f67 100644 --- a/app/apinto/profession.go +++ b/app/apinto/profession.go @@ -100,7 +100,7 @@ func ApintoProfession() []*eosc.ProfessionConfig { Label: "应用", Desc: "应用", Dependencies: nil, - AppendLabels: nil, + AppendLabels: []string{"disable"}, Drivers: []*eosc.DriverConfig{ { Id: "eolinker.com:apinto:app", diff --git a/application/app.go b/application/app.go index 982831d4..a6bd4ac0 100644 --- a/application/app.go +++ b/application/app.go @@ -40,8 +40,8 @@ func CheckSkill(skill string) bool { type IAuth interface { ID() string - Check(appID string, users []*BaseConfig) error - Set(app IApp, users []*BaseConfig) + Check(appID string, users []ITransformConfig) error + Set(app IApp, users []ITransformConfig) Del(appID string) UserCount() int IAuthUser diff --git a/application/auth/aksk/aksk.go b/application/auth/aksk/aksk.go index 726bab8d..f7a8da71 100644 --- a/application/auth/aksk/aksk.go +++ b/application/auth/aksk/aksk.go @@ -56,7 +56,7 @@ func (a *aksk) Driver() string { return driverName } -func (a *aksk) Check(appID string, users []*application.BaseConfig) error { +func (a *aksk) Check(appID string, users []application.ITransformConfig) error { us := make([]application.IUser, 0, len(users)) for _, u := range users { v, ok := u.Config().(*User) @@ -68,7 +68,7 @@ func (a *aksk) Check(appID string, users []*application.BaseConfig) error { return a.users.Check(appID, driverName, us) } -func (a *aksk) Set(app application.IApp, users []*application.BaseConfig) { +func (a *aksk) Set(app application.IApp, users []application.ITransformConfig) { infos := make([]*application.UserInfo, 0, len(users)) for _, u := range users { v, _ := u.Config().(*User) diff --git a/application/auth/aksk/config.go b/application/auth/aksk/config.go index 553a6e40..1120fc03 100644 --- a/application/auth/aksk/config.go +++ b/application/auth/aksk/config.go @@ -4,17 +4,17 @@ import "github.com/eolinker/apinto/application" type Config struct { application.Auth - Users []*User `json:"users"` + Users []*User `json:"users" label:"用户列表"` } type User struct { + Pattern Pattern `json:"pattern" label:"用户信息"` application.User - Pattern Pattern `json:"pattern"` } type Pattern struct { - AK string `json:"ak"` - SK string `json:"sk"` + AK string `json:"ak" label:"AK"` + SK string `json:"sk" label:"SK"` } func (u *User) Username() string { diff --git a/application/auth/apikey/apikey.go b/application/auth/apikey/apikey.go index 0c890867..54cb68fc 100644 --- a/application/auth/apikey/apikey.go +++ b/application/auth/apikey/apikey.go @@ -20,7 +20,7 @@ func (a *apikey) ID() string { return a.id } -func (a *apikey) Check(appID string, users []*application.BaseConfig) error { +func (a *apikey) Check(appID string, users []application.ITransformConfig) error { us := make([]application.IUser, 0, len(users)) for _, u := range users { v, ok := u.Config().(*User) @@ -32,7 +32,7 @@ func (a *apikey) Check(appID string, users []*application.BaseConfig) error { return a.users.Check(appID, driverName, us) } -func (a *apikey) Set(app application.IApp, users []*application.BaseConfig) { +func (a *apikey) Set(app application.IApp, users []application.ITransformConfig) { infos := make([]*application.UserInfo, 0, len(users)) for _, user := range users { diff --git a/application/auth/apikey/config.go b/application/auth/apikey/config.go index e6e10142..54fa2bf9 100644 --- a/application/auth/apikey/config.go +++ b/application/auth/apikey/config.go @@ -4,16 +4,16 @@ import "github.com/eolinker/apinto/application" type Config struct { application.Auth - Users []*User `json:"users"` + Users []*User `json:"users" label:"用户列表"` } type User struct { + Pattern Pattern `json:"pattern" label:"用户信息"` application.User - Pattern Pattern `json:"pattern"` } type Pattern struct { - Apikey string `json:"apikey"` + Apikey string `json:"apikey" label:"Apikey"` } func (u *User) Username() string { diff --git a/application/auth/basic/basic.go b/application/auth/basic/basic.go index c627d68c..ebb18571 100644 --- a/application/auth/basic/basic.go +++ b/application/auth/basic/basic.go @@ -53,7 +53,7 @@ func (b *basic) Driver() string { return driverName } -func (b *basic) Check(appID string, users []*application.BaseConfig) error { +func (b *basic) Check(appID string, users []application.ITransformConfig) error { us := make([]application.IUser, 0, len(users)) for _, u := range users { v, ok := u.Config().(*User) @@ -65,7 +65,7 @@ func (b *basic) Check(appID string, users []*application.BaseConfig) error { return b.users.Check(appID, driverName, us) } -func (b *basic) Set(app application.IApp, users []*application.BaseConfig) { +func (b *basic) Set(app application.IApp, users []application.ITransformConfig) { infos := make([]*application.UserInfo, 0, len(users)) for _, user := range users { v, _ := user.Config().(*User) diff --git a/application/auth/basic/config.go b/application/auth/basic/config.go index 7acfc542..3402c7e1 100644 --- a/application/auth/basic/config.go +++ b/application/auth/basic/config.go @@ -4,17 +4,17 @@ import "github.com/eolinker/apinto/application" type Config struct { application.Auth - Users []*User `json:"users"` + Users []*User `json:"users" label:"用户列表"` } type User struct { + Pattern Pattern `json:"pattern" label:"用户信息"` application.User - Pattern Pattern `json:"pattern"` } type Pattern struct { - Username string `json:"username"` - Password string `json:"password"` + Username string `json:"username" label:"用户名"` + Password string `json:"password" label:"密码"` } func (u *User) Username() string { diff --git a/application/auth/factory.go b/application/auth/factory.go index c4e89d5a..746175f3 100644 --- a/application/auth/factory.go +++ b/application/auth/factory.go @@ -64,12 +64,14 @@ func (dm *driverRegister) Set(conf interface{}) (err error) { } func (dm *driverRegister) Get() interface{} { - rs := make([]interface{}, 0, len(dm.render)) - for name, render := range dm.render { - rs = append(rs, map[string]interface{}{ - "name": name, - "render": render, - }) + rs := make([]interface{}, 0, len(dm.keys)) + for _, key := range dm.keys { + if v, ok := dm.render[key]; ok { + rs = append(rs, map[string]interface{}{ + "name": key, + "render": v, + }) + } } return rs } diff --git a/application/auth/jwt/config.go b/application/auth/jwt/config.go index 3acaf560..d0806182 100644 --- a/application/auth/jwt/config.go +++ b/application/auth/jwt/config.go @@ -12,17 +12,17 @@ import ( type Config struct { application.Auth - Config *Rule `json:"config"` - Users []*User `json:"users"` + Config *Rule `json:"config" label:"JWT配置"` + Users []*User `json:"users" label:"用户列表"` } type User struct { + Pattern Pattern `json:"pattern" label:"用户信息"` application.User - Pattern Pattern `json:"pattern"` } type Pattern struct { - Username string `json:"username"` + Username string `json:"username" label:"用户名"` } func (u *User) Username() string { @@ -30,13 +30,13 @@ func (u *User) Username() string { } type Rule struct { - Iss string `json:"iss" ` - Secret string `json:"secret"` - RsaPublicKey string `json:"rsa_public_key"` - Algorithm string `json:"algorithm"` - ClaimsToVerify []string `json:"claims_to_verify"` - SignatureIsBase64 bool `json:"signature_is_base_64"` - Path string `json:"path"` + Iss string `json:"iss" label:"签发机构"` + Algorithm string `json:"algorithm" label:"签名算法" enum:"HS256,HS384,HS512,RS256,RS384,RS512,ES256,ES384,ES512"` + Secret string `json:"secret" label:"密钥" switch:"algorithm==='HS256'||algorithm==='HS384'||algorithm==='HS512'"` + RsaPublicKey string `json:"rsa_public_key" label:"RSA公钥" switch:"algorithm!=='HS256'&&algorithm!=='HS384'&&algorithm!=='HS512'"` + Path string `json:"path" label:"用户名JsonPath"` + ClaimsToVerify []string `json:"claims_to_verify" label:"检验字段"` + SignatureIsBase64 bool `json:"signature_is_base_64" label:"签名是否base64加密" switch:"algorithm==='HS256'||algorithm==='HS384'||algorithm==='HS512'"` } func (c *Rule) ToID() (string, error) { diff --git a/application/auth/jwt/factory.go b/application/auth/jwt/factory.go index 35ffa27c..716903fe 100644 --- a/application/auth/jwt/factory.go +++ b/application/auth/jwt/factory.go @@ -1,13 +1,13 @@ package jwt import ( + "errors" "reflect" "github.com/eolinker/eosc/utils/schema" "github.com/eolinker/apinto/application" "github.com/eolinker/apinto/application/auth" - "github.com/eolinker/eosc/variable" ) var _ auth.IAuthFactory = (*factory)(nil) @@ -44,10 +44,13 @@ func (f *factory) Alias() []string { } func (f *factory) Create(tokenName string, position string, rule interface{}) (application.IAuth, error) { - cfg := &Rule{} - _, err := variable.RecurseReflect(reflect.ValueOf(rule), reflect.ValueOf(cfg), nil) - if err != nil { - return nil, err + baseConfig, ok := rule.(*application.BaseConfig) + if !ok { + return nil, errors.New("invalid jwt config") + } + cfg, ok := baseConfig.Config().(*Rule) + if !ok { + return nil, errors.New("invalid jwt config") } id, err := cfg.ToID() if err != nil { @@ -68,7 +71,7 @@ func NewFactory() auth.IAuthFactory { typ := reflect.TypeOf((*Config)(nil)) render, _ := schema.Generate(typ, nil) return &factory{ - configType: typ, + configType: reflect.TypeOf((*Rule)(nil)), render: render, userType: reflect.TypeOf((*User)(nil)), } diff --git a/application/auth/jwt/jwt.go b/application/auth/jwt/jwt.go index 6d10a239..fde4e7ea 100644 --- a/application/auth/jwt/jwt.go +++ b/application/auth/jwt/jwt.go @@ -40,7 +40,7 @@ func (j *jwt) Driver() string { return driverName } -func (j *jwt) Check(appID string, users []*application.BaseConfig) error { +func (j *jwt) Check(appID string, users []application.ITransformConfig) error { us := make([]application.IUser, 0, len(users)) for _, u := range users { v, ok := u.Config().(*User) @@ -52,7 +52,7 @@ func (j *jwt) Check(appID string, users []*application.BaseConfig) error { return j.users.Check(appID, driverName, us) } -func (j *jwt) Set(app application.IApp, users []*application.BaseConfig) { +func (j *jwt) Set(app application.IApp, users []application.ITransformConfig) { infos := make([]*application.UserInfo, 0, len(users)) for _, user := range users { v, _ := user.Config().(*User) diff --git a/application/user.go b/application/user.go index fabda996..1dc2a9f0 100644 --- a/application/user.go +++ b/application/user.go @@ -11,9 +11,9 @@ type IUser interface { } type User struct { - Expire int64 `json:"expire"` - Labels map[string]string `json:"labels"` - HideCredential bool `json:"hide_credential"` + Labels map[string]string `json:"labels" label:"用户标签"` + Expire int64 `json:"expire" label:"过期时间" format:"date-time"` + HideCredential bool `json:"hide_credential" label:"是否隐藏证书"` } type UserInfo struct { @@ -146,7 +146,7 @@ func (u *UserManager) getByAppID(appID string) ([]string, bool) { } type Auth struct { - Type string `json:"type"` - Position string `json:"position"` - TokenName string `json:"token_name"` + Type string `json:"type" label:"鉴权类型" skip:""` + Position string `json:"position" label:"token位置" enum:"header,query,body"` + TokenName string `json:"token_name" label:"token名称"` } diff --git a/drivers/app/app.go b/drivers/app/app.go index 361eb1c4..914f0282 100644 --- a/drivers/app/app.go +++ b/drivers/app/app.go @@ -93,26 +93,30 @@ func (a *app) CheckSkill(skill string) bool { return false } -func createFilters(id string, auths []*Auth) ([]application.IAuth, map[string][]*application.BaseConfig, error) { +func createFilters(id string, auths []*Auth) ([]application.IAuth, map[string][]application.ITransformConfig, error) { filters := make([]application.IAuth, 0, len(auths)) - userMap := make(map[string][]*application.BaseConfig) + userMap := make(map[string][]application.ITransformConfig) for _, v := range auths { filter, err := createFilter(v.Type, v.TokenName, v.Position, v.Config) if err != nil { return nil, nil, err } - err = checkUsers(id, filter, v.Users) + users := make([]application.ITransformConfig, 0, len(v.Users)) + for _, u := range v.Users { + users = append(users, u) + } + err = checkUsers(id, filter, users) if err != nil { return nil, nil, err } filters = append(filters, filter) - userMap[filter.ID()] = v.Users + userMap[filter.ID()] = users } return filters, userMap, nil } -func checkUsers(id string, filter application.IAuth, users []*application.BaseConfig) error { +func checkUsers(id string, filter application.IAuth, users []application.ITransformConfig) error { return filter.Check(id, users) } diff --git a/drivers/app/config.go b/drivers/app/config.go index ba395d0e..4eaeaa09 100644 --- a/drivers/app/config.go +++ b/drivers/app/config.go @@ -14,25 +14,26 @@ import ( //Config App驱动配置 type Config struct { - Auth []*Auth `json:"auth" label:"鉴权列表"` Labels map[string]string `json:"labels" label:"应用标签"` Disable bool `json:"disable" label:"是否禁用"` - Additional []*Additional `json:"additional"` + Additional []*Additional `json:"additional" label:"额外参数"` + Auth []*Auth `json:"auth" label:"鉴权列表" eotype:"interface"` } type Auth struct { - Type string `json:"type"` - Users []*application.BaseConfig `json:"users"` - Position string `json:"position"` - TokenName string `json:"token_name"` - Config *application.BaseConfig `json:"config"` + Type string `json:"type" label:"鉴权类型"` + TokenName string `json:"token_name" label:"token名称"` + Position string `json:"position" label:"token位置" enum:"header,query,body"` + Config *application.BaseConfig `json:"config" label:"配置信息" eotype:"object"` + Users []*application.BaseConfig `json:"users" label:"用户列表"` } type Additional struct { - Key string `json:"key"` - Value string `json:"value"` - Position string `json:"position" enum:"header,query,body"` - Conflict string `json:"conflict" enum:"convert,origin,error"` + Key string `json:"key" label:"参数名"` + Value string `json:"value" label:"参数值"` + Position string `json:"position" label:"参数位置" enum:"header,query,body"` + Conflict string `json:"conflict" label:"参数存在替换规则" enum:"convert,origin,error"` + Labels map[string]string `json:"labels"` } func (a *Auth) Reset(originVal reflect.Value, targetVal reflect.Value, variables eosc.IVariable) ([]string, error) { @@ -46,7 +47,6 @@ func (a *Auth) Reset(originVal reflect.Value, targetVal reflect.Value, variables if err != nil { return nil, err } - log.Debug("set type: ", string(bytes)) f, err := auth.GetFactory(tmp.Type) if err != nil { diff --git a/drivers/app/extend-param.go b/drivers/app/extend-param.go index 1e44c150..bca655da 100644 --- a/drivers/app/extend-param.go +++ b/drivers/app/extend-param.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "mime" + "net/http" "net/textproto" "strings" @@ -39,6 +40,9 @@ func (a *additionalParam) Execute(ctx http_service.IHttpContext) error { } switch p.Position { case application.PositionBody: + if ctx.Proxy().Method() != http.MethodPost && ctx.Proxy().Method() != http.MethodPut && ctx.Proxy().Method() != http.MethodPatch { + continue + } switch contentType { case http_context.FormData, http_context.MultipartForm: switch p.Conflict { @@ -129,6 +133,9 @@ func (a *additionalParam) Execute(ctx http_service.IHttpContext) error { } func parseBodyParams(ctx http_service.IHttpContext) (interface{}, map[string][]string, error) { + if ctx.Proxy().Method() != http.MethodPost && ctx.Proxy().Method() != http.MethodPut && ctx.Proxy().Method() != http.MethodPatch { + return nil, nil, nil + } contentType, _, _ := mime.ParseMediaType(ctx.Proxy().Body().ContentType()) switch contentType { case http_context.FormData, http_context.MultipartForm: @@ -142,6 +149,9 @@ func parseBodyParams(ctx http_service.IHttpContext) (interface{}, map[string][]s if err != nil { return nil, nil, err } + if string(body) == "" { + body = []byte("{}") + } bodyParams, err := oj.Parse(body) return bodyParams, nil, err } diff --git a/drivers/app/manager/manager.go b/drivers/app/manager/manager.go index db7ee1f5..66414a23 100644 --- a/drivers/app/manager/manager.go +++ b/drivers/app/manager/manager.go @@ -16,7 +16,7 @@ type IManager interface { Get(id string) (application.IAuth, bool) List() []application.IAuthUser ListByDriver(driver string) []application.IAuthUser - Set(app application.IApp, filters []application.IAuth, users map[string][]*application.BaseConfig) + Set(app application.IApp, filters []application.IAuth, users map[string][]application.ITransformConfig) Del(appID string) Count() int } @@ -100,7 +100,7 @@ func (m *Manager) All() []application.IAuthUser { return m.all() } -func (m *Manager) Set(app application.IApp, filters []application.IAuth, users map[string][]*application.BaseConfig) { +func (m *Manager) Set(app application.IApp, filters []application.IAuth, users map[string][]application.ITransformConfig) { idMap := make(map[string][]string) for _, filter := range filters { f, has := m.get(filter.ID()) diff --git a/drivers/plugins/extra-params/extra-params.go b/drivers/plugins/extra-params/extra-params.go index 32e81304..7b509f31 100644 --- a/drivers/plugins/extra-params/extra-params.go +++ b/drivers/plugins/extra-params/extra-params.go @@ -5,9 +5,12 @@ import ( "errors" "fmt" "mime" + "net/http" "strconv" "strings" + "github.com/ohler55/ojg/jp" + http_context "github.com/eolinker/apinto/node/http-context" "github.com/eolinker/eosc" "github.com/eolinker/eosc/eocontext" @@ -17,6 +20,10 @@ import ( var _ http_service.HttpFilter = (*ExtraParams)(nil) var _ eocontext.IFilter = (*ExtraParams)(nil) +var ( + errorExist = "%s: %s is already exists" +) + type ExtraParams struct { *Driver id string @@ -84,7 +91,11 @@ func (e *ExtraParams) access(ctx http_service.IHttpContext) (int, error) { } case "body": { - if strings.Contains(contentType, http_context.FormData) || strings.Contains(contentType, http_context.MultipartForm) { + if ctx.Proxy().Method() != http.MethodPost && ctx.Proxy().Method() != http.MethodPut && ctx.Proxy().Method() != http.MethodPatch { + continue + } + switch contentType { + case http_context.FormData, http_context.MultipartForm: if _, has := formParams[param.Name]; has { switch param.Conflict { case paramConvert: @@ -98,23 +109,57 @@ func (e *ExtraParams) access(ctx http_service.IHttpContext) (int, error) { } else { formParams[param.Name] = []string{paramValue.(string)} } - } else if strings.Contains(contentType, http_context.JSON) { - if _, has := bodyParams[param.Name]; has { + case http_context.JSON: + { + key := param.Name + if !strings.HasPrefix(param.Name, "$.") { + key = "$." + key + } + x, err := jp.ParseString(key) + if err != nil { + return 400, fmt.Errorf("parse key error: %v", err) + } switch param.Conflict { case paramConvert: - bodyParams[param.Name] = paramValue.(string) - case paramOrigin: - case paramError: - return clientErrStatusCode, errors.New(`[extra_params] "` + param.Name + `" has a conflict.`) - default: - bodyParams[param.Name] = paramValue + err = x.Set(bodyParams, param.Value) + if err != nil { + return 400, fmt.Errorf("set additional json param error: %v", err) + } + case paramOrigin, paramError: + { + result := x.Get(bodyParams) + if len(result) < 1 { + err = x.Set(bodyParams, param.Value) + if err != nil { + return 400, fmt.Errorf("set additional json param error: %v", err) + } + } + if param.Conflict == paramError { + return 400, fmt.Errorf(errorExist, param.Position, param.Name) + } + } } - } else { - bodyParams[param.Name] = paramValue } } - } + //if strings.Contains(contentType, http_context.FormData) || strings.Contains(contentType, http_context.MultipartForm) { + // + //} else if strings.Contains(contentType, ) { + // if _, has := bodyParams[param.Name]; has { + // switch param.Conflict { + // case paramConvert: + // bodyParams[param.Name] = paramValue.(string) + // case paramOrigin: + // case paramError: + // return clientErrStatusCode, errors.New(`[extra_params] "` + param.Name + `" has a conflict.`) + // default: + // bodyParams[param.Name] = paramValue + // } + // } else { + // bodyParams[param.Name] = paramValue + // } + //} + } } if strings.Contains(contentType, http_context.FormData) || strings.Contains(contentType, http_context.MultipartForm) { diff --git a/drivers/plugins/extra-params/util.go b/drivers/plugins/extra-params/util.go index 3bea2030..fc5b93a7 100644 --- a/drivers/plugins/extra-params/util.go +++ b/drivers/plugins/extra-params/util.go @@ -5,8 +5,11 @@ import ( "errors" "fmt" "mime" + "net/http" "strings" + "github.com/ohler55/ojg/oj" + http_context "github.com/eolinker/apinto/node/http-context" http_service "github.com/eolinker/eosc/eocontext/http-context" ) @@ -42,9 +45,11 @@ func encodeErr(ent string, origin string, statusCode int) error { return fmt.Errorf("%s statusCode: %d", origin, statusCode) } -func parseBodyParams(ctx http_service.IHttpContext) (map[string]interface{}, map[string][]string, error) { +func parseBodyParams(ctx http_service.IHttpContext) (interface{}, map[string][]string, error) { + if ctx.Proxy().Method() != http.MethodPost && ctx.Proxy().Method() != http.MethodPut && ctx.Proxy().Method() != http.MethodPatch { + return nil, nil, nil + } contentType, _, _ := mime.ParseMediaType(ctx.Proxy().Body().ContentType()) - switch contentType { case http_context.FormData, http_context.MultipartForm: formParams, err := ctx.Proxy().Body().BodyForm() @@ -57,15 +62,40 @@ func parseBodyParams(ctx http_service.IHttpContext) (map[string]interface{}, map if err != nil { return nil, nil, err } - var bodyParams map[string]interface{} - err = json.Unmarshal(body, &bodyParams) - if err != nil { - return bodyParams, nil, err + if string(body) == "" { + body = []byte("{}") } + bodyParams, err := oj.Parse(body) + return bodyParams, nil, err } - return nil, nil, errors.New("[params_transformer] unsupported content-type: " + contentType) + return nil, nil, errors.New("unsupported content-type: " + contentType) } +// +//func parseBodyParams(ctx http_service.IHttpContext) (map[string]interface{}, map[string][]string, error) { +// contentType, _, _ := mime.ParseMediaType(ctx.Proxy().Body().ContentType()) +// +// switch contentType { +// case http_context.FormData, http_context.MultipartForm: +// formParams, err := ctx.Proxy().Body().BodyForm() +// if err != nil { +// return nil, nil, err +// } +// return nil, formParams, nil +// case http_context.JSON: +// body, err := ctx.Proxy().Body().RawBody() +// if err != nil { +// return nil, nil, err +// } +// var bodyParams map[string]interface{} +// err = json.Unmarshal(body, &bodyParams) +// if err != nil { +// return bodyParams, nil, err +// } +// } +// return nil, nil, errors.New("[params_transformer] unsupported content-type: " + contentType) +//} + func getHeaderValue(headers map[string][]string, param *ExtraParam, value string) (string, error) { paramName := ConvertHeaderKey(param.Name)