1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
package openapi3filter
import (
"context"
"net/http"
"github.com/getkin/kin-openapi/openapi3"
"github.com/getkin/kin-openapi/routers"
legacyrouter "github.com/getkin/kin-openapi/routers/legacy"
)
// AuthenticationFunc allows for custom security requirement validation.
// A non-nil error fails authentication according to https://spec.openapis.org/oas/v3.1.0#security-requirement-object
// See ValidateSecurityRequirements
type AuthenticationFunc func(context.Context, *AuthenticationInput) error
// NoopAuthenticationFunc is an AuthenticationFunc
func NoopAuthenticationFunc(context.Context, *AuthenticationInput) error { return nil }
var _ AuthenticationFunc = NoopAuthenticationFunc
type ValidationHandler struct {
Handler http.Handler
AuthenticationFunc AuthenticationFunc
File string
ErrorEncoder ErrorEncoder
router routers.Router
}
func (h *ValidationHandler) Load() error {
loader := openapi3.NewLoader()
doc, err := loader.LoadFromFile(h.File)
if err != nil {
return err
}
if err := doc.Validate(loader.Context); err != nil {
return err
}
if h.router, err = legacyrouter.NewRouter(doc); err != nil {
return err
}
// set defaults
if h.Handler == nil {
h.Handler = http.DefaultServeMux
}
if h.AuthenticationFunc == nil {
h.AuthenticationFunc = NoopAuthenticationFunc
}
if h.ErrorEncoder == nil {
h.ErrorEncoder = DefaultErrorEncoder
}
return nil
}
func (h *ValidationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if handled := h.before(w, r); handled {
return
}
// TODO: validateResponse
h.Handler.ServeHTTP(w, r)
}
// Middleware implements gorilla/mux MiddlewareFunc
func (h *ValidationHandler) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handled := h.before(w, r); handled {
return
}
// TODO: validateResponse
next.ServeHTTP(w, r)
})
}
func (h *ValidationHandler) before(w http.ResponseWriter, r *http.Request) (handled bool) {
if err := h.validateRequest(r); err != nil {
h.ErrorEncoder(r.Context(), err, w)
return true
}
return false
}
func (h *ValidationHandler) validateRequest(r *http.Request) error {
// Find route
route, pathParams, err := h.router.FindRoute(r)
if err != nil {
return err
}
options := &Options{
AuthenticationFunc: h.AuthenticationFunc,
}
// Validate request
requestValidationInput := &RequestValidationInput{
Request: r,
PathParams: pathParams,
Route: route,
Options: options,
}
if err = ValidateRequest(r.Context(), requestValidationInput); err != nil {
return err
}
return nil
}
|