我正在使用Gox作为路由器并使用Negroni来管理API的中间件,从而在Golang中构建了一个Web应用。
我有以下中间件:
我想适当地将中间件应用于特定的路由,即对所有请求使用CORS中间件,并仅在受保护的路由上检查auth。
当我尝试使用前端发出API请求时,对我来说实际上发生了什么,那就是CORS中间件似乎只是针对每个API路由的初始OPTIONS请求而被调用,而没有被随后使用。
例如:
在其他一些路线上,我们也看到了奇怪的事情-例如,在向/ api / entities发出Postman GET请求时,我们能够在未登录时获取实体列表(应受到保护)。身份验证中间件没有被调用或表现不正常。
我对其中的一些概念还很陌生,所以也许我误解了一些东西。任何帮助将不胜感激。
我的代码如下(main.go):
router := mux.NewRouter()
router.HandleFunc("/", ServeUI).Methods("GET")
apiRouter := router.PathPrefix("/api").Subrouter()
authRouter := apiRouter.PathPrefix("/auth").Subrouter()
authRouter.HandleFunc("/login", HandleLogin).Methods("POST")
authRouter.HandleFunc("/logout", HandleLogout).Methods("POST")
entitiesRouter := apiRouter.PathPrefix("/entities").Subrouter()
entitiesRouter.HandleFunc("/", GetEntities).Methods("GET")
commonAPIMiddleware := negroni.New(corsMiddleware.NewCorsMiddleware())
router.PathPrefix("/api/auth").Handler(commonAPIMiddleware.With(
negroni.Wrap(authRouter),
))
router.PathPrefix("/api/entities").Handler(commonAPIMiddleware.With(
auth.NewAPIAuthMiddleware(),
negroni.Wrap(entitiesRouter),
))
n := negroni.New(negronilogrus.NewMiddleware())
n.UseHandler(router)
n.Run(":8009")
corsMiddleware的代码如下:
// CorsMiddleware allows CORS request for api routes
type CorsMiddleware struct {
}
// Negroni compatible interface
func (m *CorsMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
log.Info("CORS MIDDLEWARE CALLED")
if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
log.Info("ServeHTTP: Preflight request")
handlePreflight(w, r)
// Preflight requests are standalone and should stop the chain as some other
// middleware may not handle OPTIONS requests correctly. One typical example
// is authentication middleware ; OPTIONS requests won't carry authentication
// headers (see #1)
w.WriteHeader(http.StatusOK)
} else {
log.Info("ServeHTTP: Actual request")
handleActualRequest(w, r)
next(w, r)
}
}
// handlePreflight handles pre-flight CORS requests
func handlePreflight(w http.ResponseWriter, r *http.Request) {
headers := w.Header()
origin := r.Header.Get("Origin")
if r.Method != http.MethodOptions {
log.Info(" Preflight aborted: %s!=OPTIONS", r.Method)
return
}
// Always set Vary headers
// see https://github.com/rs/cors/issues/10,
// https://github.com/rs/cors/commit/dbdca4d95feaa7511a46e6f1efb3b3aa505bc43f#commitcomment-12352001
headers.Add("Vary", "Origin")
headers.Add("Vary", "Access-Control-Request-Method")
headers.Add("Vary", "Access-Control-Request-Headers")
if origin == "" {
log.Info(" Preflight aborted: empty origin")
return
}
headers.Set("Access-Control-Allow-Origin", origin)
// Spec says: Since the list of methods can be unbounded, simply returning the method indicated
// by Access-Control-Request-Method (if supported) can be enough
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
headers.Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, X-Requested-With")
headers.Set("Access-Control-Allow-Credentials", "true")
headers.Set("Access-Control-Max-Age", strconv.Itoa(1000))
log.Info(" Preflight response headers: %v", headers)
}
// handleActualRequest handles simple cross-origin requests, actual request or redirects
func handleActualRequest(w http.ResponseWriter, r *http.Request) {
log.Info("CORS HANDLING ACTUAL REQUEST")
headers := w.Header()
origin := r.Header.Get("Origin")
if r.Method == http.MethodOptions {
log.Info(" Actual request no headers added: method == %s", r.Method)
return
}
// Always set Vary, see https://github.com/rs/cors/issues/10
headers.Add("Vary", "Origin")
if origin == "" {
log.Info(" Actual request no headers added: missing origin")
return
}
headers.Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, X-Requested-With")
headers.Set("Access-Control-Allow-Credentials", "true")
headers.Set("Access-Control-Allow-Origin", origin)
if true {
headers.Set("Access-Control-Allow-Credentials", "true")
}
}