如何使用中间件包装API端点

时间:2019-04-02 15:46:09

标签: go

AM尝试生成并应用客户端凭据访问令牌来包装简单的API端点。当所有代码都在main函数中时,我得到了运行良好的代码。但是,我想将API端点(/受保护的)与主要功能之外的中间函数一起放在中间目录的另一个目录中。 我该怎么做,以便中间件适用于对服务器的每个请求?

我在父目录中的主要功能

func main() {
    log.Printf("Server started")

    router := sw.NewRouter()
    manager := manage.NewDefaultManager()
    manager.SetAuthorizeCodeTokenCfg(manage.DefaultAuthorizeCodeTokenCfg)

    manager.MustTokenStorage(store.NewMemoryTokenStore())

    clientStore := store.NewClientStore()
    manager.MapClientStorage(clientStore)

    srv := server.NewDefaultServer(manager)
    srv.SetAllowGetAccessRequest(true)
    srv.SetClientInfoHandler(server.ClientFormHandler)
    manager.SetRefreshTokenCfg(manage.DefaultRefreshTokenCfg)

    srv.SetInternalErrorHandler(func(err error) (re *errors.Response) {
        log.Println("Internal Error:", err.Error())
        return
    })

    srv.SetResponseErrorHandler(func(re *errors.Response) {
        log.Println("Response Error:", re.Error.Error())
    })

    router.HandleFunc("/oauth2/token", func(w http.ResponseWriter, r *http.Request) {
        srv.HandleTokenRequest(w, r)
    })

    router.HandleFunc("/credentials", func(w http.ResponseWriter, r *http.Request) {
        clientId := uuid.New().String()[:8]
        clientSecret := uuid.New().String()[:8]
        err := clientStore.Set(clientId, &models.Client{
            ID:     clientId,
            Secret: clientSecret,
            Domain: "http://localhost:9094",
        })
        if err != nil {
            fmt.Println(err.Error())
        }

        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(map[string]string{"CLIENT_ID": clientId, "CLIENT_SECRET": clientSecret})
    })

    log.Fatal(http.ListenAndServe(":8000", router))
}


middleware API endpoint and router in a sub directory


func protecteduri(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello, I'm protected"))
}

func validateToken(f http.HandlerFunc, srv *server.Server) http.HandlerFunc {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        _, err := srv.ValidationBearerToken(r)
        if err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }

        f.ServeHTTP(w, r)
    })
}


router

type Route struct {
    Name        string
    Method      string
    Pattern     string
    HandlerFunc http.HandlerFunc
}

type Routes []Route

func NewRouter() *mux.Router {
    router := mux.NewRouter().StrictSlash(true)
    for _, route := range routes {
        var handler http.Handler
        handler = route.HandlerFunc
        handler = Logger(handler, route.Name)

        router.
            Methods(route.Method).
            Path(route.Pattern).
            Name(route.Name).
            Handler(handler)
    }

    return router
}

func Index(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World!")
}

var routes = Routes{
    {
        "Index",
        "GET",
        "/",
        Index,
    },

    {
        "protecteduri",
        strings.ToUpper("Get"),
        "/protected",
        protecteduri,
    },

    {
        "AccessTokenRequest",
        strings.ToUpper("Post"),
        "/oauth2/token",
        AccessTokenRequest,
    },
}

通常我在路由器文件中将中间件添加为

hadler =中间件(处理程序)

,它适用于所有传入请求,但在这种情况下,它不适用 工作。

完整的工作代码是这个

func main() {
   manager := manage.NewDefaultManager()
   manager.SetAuthorizeCodeTokenCfg(manage.DefaultAuthorizeCodeTokenCfg)

   // token memory store
   manager.MustTokenStorage(store.NewMemoryTokenStore())

   // client memory store
   clientStore := store.NewClientStore()

   manager.MapClientStorage(clientStore)

   srv := server.NewDefaultServer(manager)
   srv.SetAllowGetAccessRequest(true)
   srv.SetClientInfoHandler(server.ClientFormHandler)
   manager.SetRefreshTokenCfg(manage.DefaultRefreshTokenCfg)

   srv.SetInternalErrorHandler(func(err error) (re *errors.Response) {
      log.Println("Internal Error:", err.Error())
      return
   })

   srv.SetResponseErrorHandler(func(re *errors.Response) {
      log.Println("Response Error:", re.Error.Error())
   })

   http.HandleFunc("/oauth2/token", func(w http.ResponseWriter, r *http.Request) {
      srv.HandleTokenRequest(w, r)
   })

   http.HandleFunc("/credentials", func(w http.ResponseWriter, r *http.Request) {
      clientId := uuid.New().String()[:8]
      clientSecret := uuid.New().String()[:8]
      err := clientStore.Set(clientId, &models.Client{
         ID:     clientId,
         Secret: clientSecret,
         Domain: "http://localhost:9094",
      })
      if err != nil {
         fmt.Println(err.Error())
      }

      w.Header().Set("Content-Type", "application/json")
      json.NewEncoder(w).Encode(map[string]string{"CLIENT_ID": clientId, "CLIENT_SECRET": clientSecret})
   })

   http.HandleFunc("/protected", validateToken(func(w http.ResponseWriter, r *http.Request) {
      w.Write([]byte("Hello, I'm protected"))
   }, srv))

   log.Fatal(http.ListenAndServe(":9096", nil))
}

//main function end here
//middleware function below

func validateToken(f http.HandlerFunc, srv *server.Server) http.HandlerFunc {
   return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
      _, err := srv.ValidationBearerToken(r)
      if err != nil {
         http.Error(w, err.Error(), http.StatusBadRequest)
         return
      }

      f.ServeHTTP(w, r)
   })
}

如您所见,请求此句柄函数http.HandleFunc(“ / protected” ...的访问令牌已使用中间件函数“ validateToken”进行了验证。

http.HandleFunc("/protected", validateToken(func(w http.ResponseWriter, r *http.Request) {
      w.Write([]byte("Hello, I'm protected"))
   }, srv))

我想做的是通过将路由句柄函数(http.HandleFunc(“ / protected” ...)移到主函数之外来重写主函数,并且当我向主机发送请求时仍对访问令牌进行验证。 (http.HandleFunc(“ / protected”,validateToken(...)函数使用上面定义的路由。在安全代码中,它可以工作,但handlefunction的令牌

func protecteduri(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello, I'm protected"))
}

未经验证。

我将添加更多的句柄函数,并且不想将它们全部放入主函数中。

http.HandleFunc("/protected", validateToken(func(w http.ResponseWriter, r *http.Request) {
      w.Write([]byte("Hello, I'm protected"))
   }, srv))

0 个答案:

没有答案
相关问题