Я создаю веб-приложение на Голанге, используя mux в качестве маршрутизатора и Negroni для управления промежуточным ПО для API.
У меня есть следующее промежуточное ПО:
- Промежуточное ПО аутентификации, котороепроверяет, что клиент имеет действительный сеанс, и возвращает 401, если не
- Промежуточное программное обеспечение, чтобы разрешить запросы CORS, основанные на отредактированной версии https://github.com/rs/cors/
Я хочу применить промежуточное ПОв зависимости от конкретных маршрутов, т. е. с использованием промежуточного программного обеспечения CORS для всех запросов и проверки аутентификации только на защищенных маршрутах.
Что действительно происходит со мной, когда я пытаюсь выполнять запросы API с использованием внешнего интерфейса, так это то, что промежуточное программное обеспечение CORSКажется, он вызывается только для первоначального запроса OPTIONS для каждого маршрута API и впоследствии не используется.
Например:
- Пользовательский интерфейс выполняет POST для / api / login с JSONобъект, содержащий учетные данные
- В консоли обозревателя мы видим, что первоначальный запрос OPTIONS перед полетом получает 200 OK со всемиЗаголовки, которые мы устанавливаем с помощью handlePreflight в corsMiddleware, пока что хороши.
- Тогда ни один из последующих запросов POST не попал в corsMiddleware.Мы знаем, что промежуточное программное обеспечение никогда не вызывается, поскольку мы никогда не видим его вызываемым в журнале сервера.Мы получаем сообщение об ошибке «Нет заголовка« Access-Control-Allow-Origin »на запрашиваемом ресурсе» в Chrome.
- Странно то, что функция handleLogin действительно вызывается ,мы можем видеть правильные учетные данные, и кажется, что сервер правильно хранит сеанс для них.
Мы также видим странные вещи на некоторых других маршрутах - то есть, когда отправляем GET-запросы Postman к / api/ entity мы можем получить список сущностей (которые должны быть защищены), когда не вошли в систему. Это похоже на то, что промежуточное ПО аутентификации не вызывается или не ведет себя должным образом.
Я довольно новичокк некоторым из этих концепций, так что, возможно, я что-то неправильно понял.Буду признателен за любую помощь.
Мой код выглядит следующим образом (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")
}
}