Аутентифицировать пользователей при определенных запросах дескриптора

#rest #go #mux

#rest #Вперед #Мультиплексирование

Вопрос:

Существует ли более эффективный способ аутентификации пользователей при определенных запросах дескриптора? Прямо сейчас я вызываю функцию для аутентификации на основе токена запроса, но делаю это для каждой функции дескриптора.

 func GetCompanies(w http.ResponseWriter, r *http.Request) {
    //Authentication
    token := r.Header.Get("Authorization")
    err := auth.AuthenticateUser(token)
    if err != nil {
        if custom, ok := err.(*errors.MyErrorType); ok {
            fmt.Println(custom.Error())
            w.WriteHeader(custom.Code)
            _ = json.NewEncoder(w).Encode("Error: "   custom.Msg)
        } else {
            fmt.Println(err)
            w.WriteHeader(500)
        }
        return
    }
    //If user is authenticated do other stuff
}
  

Я пробовал использовать промежуточное программное обеспечение, но оно выполняется для каждой функции дескриптора. Я хочу, чтобы пользователи, не прошедшие проверку подлинности, получали доступ к определенным API

 func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Do stuff here
        fmt.Println(r.URL)
        // Call the next handler, which can be another middleware in the chain, or the final handler.
        next.ServeHTTP(w, r)
    })
}

func HandleFunctions() {
    //Init Router
    r := mux.NewRouter()
    r.Use(loggingMiddleware)

    //API Paths that do not require Auth
        r.HandleFunc("/login", handlers.Authenticate).Methods("POST")
        //API Paths that require auth
        r.HandleFunc("/stuff", handlers.PostThings).Methods("POST")
}
  

Я также хочу иметь возможность реализовывать роли пользователей в будущем, чтобы в зависимости от разрешений безопасности были доступны разные пути или нет.

Какой наиболее эффективный способ сделать это?

Ответ №1:

На самом деле вам не нужно промежуточное программное обеспечение для этого. Вы можете достичь этого, обернув свои обработчики в общую функцию аутентификации. Взгляните на приведенный ниже код, я думаю, он сделает то, что вы ищете.

     func grant(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {

            //Place your logic to authenticate users here
            //This is only a snippet. You have to adapt the code to your needs.

            token := r.Header.Get("Authorization")
            if err := auth.AuthenticateUser(token); err != nil {
                //If error is returned. The grant function will return error
                // and abort execution and therefore not reaching your handler
                http.Error(w, "Authentication is Invalid", http.StatusInternalServerError)
                return
            }
            //If Authentication is valid your handler function will be executed
            fn(w, r)
        }
    }


    // Define your handler functions as you'd normally do
    func handler(w http.ResponseWriter, r *http.Request) {
      fmt.Fprint(w,"Success")
    }


    func main() {
      //Then wrap the handlers that need authentication around the grant function
      http.HandleFunc("/your/url/path", grant(handler))

      //For endpoints that don't need authentication, simply pass the handler as usual without the grant function
      http.HandleFunc("/your/url/path/noauth", anotherHandler)
    }
  

Функция «grant» принимает функцию типа http.HandlerFunc в качестве аргумента. Который в данном случае является самим обработчиком.

функциональный обработчик (w http.ResponseWriter, r * http.Запрос)

Следовательно, функция должна иметь http.ResponseWriter и *http.Запрашивать в качестве аргументов. Что является тем же самым, что требуется http.Функция обработки.

http.HandleFunc(«/ваш/url/путь», обработчик)

То, что делает функция grant, в основном принимает ваш обработчик в качестве аргумента, и если все идет хорошо, grant выполняет ваш обработчик таким же образом, как http.HandleFunc бы подошел.

fn (w, r)

Если аутентификация завершится неудачей, grant вернет ошибку и никогда не достигнет выполнения вашего обработчика.

Комментарии:

1. Это сработало. Не могли бы вы объяснить части этой функции, чтобы я понял, что происходит? unc grant(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request)