如何在使用golang http包时限制客户端IP地址

Wil*_*Lee 3 http go

我正在使用golang http包.服务器如何限制客户端IP地址?

func (s *Worker) Run(c chan error) {
    apiMux := http.NewServeMux()
    apiMux.HandleFunc("/test", s.test)
    apiMux.HandleFunc("/block/create", s.CreateBlock)
    apiMux.HandleFunc("/block/delete", s.DeleteBlock)

    apiServer := &http.Server{
        Addr:    "0.0.0.0:" + strconv.Itoa(s.ListenPort),
        Handler: apiMux,
    }

    go func() {
        log.Println("Worker listening on " + apiServer.Addr)
        c <- apiServer.ListenAndServe()
    }()
}
Run Code Online (Sandbox Code Playgroud)

Not*_*fer 7

您需要做两件事:一个是使用中间件处理程序包装您的多路复用器,该处理程序预处理您的请求并验证IP.另一个是获取用户的真实IP,如果您位于防火墙或负载均衡器后面(导致地址始终是LB的地址),或者如果您的用户位于代理后面,这一点非常重要.

至于包装你的多路复用器,它很简单:

apiServer := &http.Server{
    Addr:    "0.0.0.0:8080",
    Handler: http.HandlerFunc( func(w http.ResponseWriter, req *http.Request) {
        // get the real IP of the user, see below
        addr := getRealAddr(req)

       // the actual vaildation - replace with whatever you want
       if (addr != "1.2.3.4") {
            http.Error(w, "Blocked", 401)
            return
        }
        // pass the request to the mux
        apiMux.ServeHTTP(w,req)
    }),
}
Run Code Online (Sandbox Code Playgroud)

而且我附加了一个getRealAddr函数,它来自一个实际的项目,我做了这样的事情:

func getRealAddr(r *http.Request)  string {

    remoteIP := ""
    // the default is the originating ip. but we try to find better options because this is almost
    // never the right IP
    if parts := strings.Split(r.RemoteAddr, ":"); len(parts) == 2 {
        remoteIP = parts[0]
    }
    // If we have a forwarded-for header, take the address from there
    if xff := strings.Trim(r.Header.Get("X-Forwarded-For"), ","); len(xff) > 0 {
        addrs := strings.Split(xff, ",")
        lastFwd := addrs[len(addrs)-1]
        if ip := net.ParseIP(lastFwd); ip != nil {
            remoteIP = ip.String()
        }
    // parse X-Real-Ip header
    } else if xri := r.Header.Get("X-Real-Ip"); len(xri) > 0 {
        if ip := net.ParseIP(xri); ip != nil {
            remoteIP = ip.String()
        }
    }

    return remoteIP

}
Run Code Online (Sandbox Code Playgroud)

至于过滤,它可以基于一组ips或CIDR范围,当然,这取决于你.

如果您有兴趣,上面的代码来自我编写的一个API构建工具包,名为Vertex,它内置了这个:https://github.com/EverythingMe/vertex

  • 要注意的一件事是,如果运行此代码的计算机启用了ipv6,则地址可能采用`[::]:&lt;port&gt;格式。例如,当我在本地服务并请求时,r.RemoteAddr返回`[:: 1]:32445`(端口可能会有所不同) (2认同)