Я пытаюсь создать маршруты, используя gorilla/mux
, некоторые из которых должны быть защищены базовым auth, а другие не должны. В частности, для каждого маршрута под кодом /v2
требуется базовое auth, но маршруты под /health
должны быть общедоступными.Невозможно защитить gorilla/mux Subroute с базовым auth
Как вы можете видеть ниже, я могу обернуть каждый из моих обработчиков маршрутов /v2
с помощью BasicAuth()
, но это противоречит принципу DRY, а также подверженности ошибкам, не говоря уже о последствиях безопасности для забывания обернуть один из этих обработчиков.
У меня есть следующий вывод от curl
. Все, кроме последнего, я ожидаю. Нельзя удалять GET
/smallcat
без аутентификации.
$ curl localhost:3000/health/ping
"PONG"
$ curl localhost:3000/health/ping/
404 page not found
$ curl localhost:3000/v2/bigcat
Unauthorised.
$ curl apiuser:[email protected]:3000/v2/bigcat
"Big MEOW"
$ curl localhost:3000/v2/smallcat
"Small Meow"
Полный код. Я считаю, что мне нужно как-то исправить определение v2Router
, но не могу понять, как это сделать.
package main
import (
"crypto/subtle"
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
)
func endAPICall(w http.ResponseWriter, httpStatus int, anyStruct interface{}) {
result, err := json.MarshalIndent(anyStruct, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(httpStatus)
w.Write(result)
}
func BasicAuth(handler http.HandlerFunc, username, password, realm string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user, pass, ok := r.BasicAuth()
if !ok || subtle.ConstantTimeCompare([]byte(user), []byte(username)) != 1 || subtle.ConstantTimeCompare([]byte(pass), []byte(password)) != 1 {
w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
w.WriteHeader(401)
w.Write([]byte("Unauthorised.\n"))
return
}
handler(w, r)
}
}
func routers() *mux.Router {
username := "apiuser"
password := "apipass"
noopHandler := func(http.ResponseWriter, *http.Request) {}
topRouter := mux.NewRouter().StrictSlash(false)
healthRouter := topRouter.PathPrefix("/health/").Subrouter()
v2Router := topRouter.PathPrefix("/v2").HandlerFunc(BasicAuth(noopHandler, username, password, "Provide username and password")).Subrouter()
healthRouter.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
endAPICall(w, 200, "PONG")
})
v2Router.HandleFunc("/smallcat", func(w http.ResponseWriter, r *http.Request) {
endAPICall(w, 200, "Small Meow")
})
bigMeowFn := func(w http.ResponseWriter, r *http.Request) {
endAPICall(w, 200, "Big MEOW")
}
v2Router.HandleFunc("/bigcat", BasicAuth(bigMeowFn, username, password, "Provide username and password"))
return topRouter
}
func main() {
if r := routers(); r != nil {
log.Fatal("Server exited:", http.ListenAndServe(":3000", r))
}
}
Приложение оборачивает обработчик/v2 только. Оберните каждый обработчик. –
Пакеты 'goji/httpauth' утверждают, что защищают все маршруты только одной оберткой вокруг корневого обработчика. См. Их пример в https://github.com/goji/httpauth#gorillamux. Я попытался использовать этот пакет для защиты '/ v2' тоже, но без каких-либо успехов. –
Возможно, вам понадобится что-то вроде промежуточного слоя для выполнения такой работы: https://github.com/urfave/negroni – ymonad