golang 反向代理,支持 token 鉴权

go-proxy-pass.go

package main

import (
    "flag"
    "fmt"
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
    "os"
    "strconv"
    "strings"
    "time"
)

const (
    timeFormat = "2006/01/02 15:04:05"
)

// 获取当前时间
func NowTimeStr() string {
    return time.Now().Format(timeFormat)
}

// NewProxy 拿到 targetHost 后,创建一个反向代理
func NewProxy(targetHost string) (*httputil.ReverseProxy, error) {
    url, err := url.Parse(targetHost)
    if err != nil {
        return nil, err
    }

    return httputil.NewSingleHostReverseProxy(url), nil
}

// ProxyRequestHandler 使用 proxy 处理请求
func ProxyRequestHandler(proxy *httputil.ReverseProxy, token string) func(http.ResponseWriter, *http.Request) {
    return func(w http.ResponseWriter, r *http.Request) {
        if (token == "" || token == r.Header.Get("token")) {
            proxy.ServeHTTP(w, r)
        } else {
            w.WriteHeader(403)
            w.Header().Set("Content-Type","application/json")
            w.Write([]byte(`{"code":403,"msg":"ERROR 请求头token不合法,或为空"}` + "\n"))
            fmt.Println(NowTimeStr() + " ERROR 请求头token不合法,或为空")
        }
        
    }
}

func main() {
    port := flag.Int("port", -1, "服务端口")
    proxy_pass := flag.String("proxy_pass", "", "反向代理地址")
    token := flag.String("token", "", "鉴权token")
    flag.Parse()

    if (*port >= 1025 && *port <= 65535) {
        fmt.Println(NowTimeStr() + " INFO 端口号【port】: " + strconv.Itoa(*port))
    } else {
        fmt.Println(NowTimeStr() + " ERROR 端口号【port】取值范围:[ 1025 - 65535 ]")
        os.Exit(1)
    }

    if (strings.HasPrefix(*proxy_pass, "http://") || strings.HasPrefix(*proxy_pass, "https://")) {
        fmt.Println(NowTimeStr() + " INFO 反向代理地址【proxy_pass】: " + *proxy_pass)
    } else {
        fmt.Println(NowTimeStr() + " ERROR 反向代理地址【proxy_pass】不合法")
        os.Exit(1)
    }

    if (*token != "") {
        fmt.Println(NowTimeStr() + " INFO 鉴权token【token】: " + *token)
    }

    // 初始化反向代理并传入真正后端服务的地址
    proxy, err := NewProxy(*proxy_pass)
    if err != nil {
        panic(err)
    }

    // 使用 proxy 处理所有请求到你的服务
    http.HandleFunc("/", ProxyRequestHandler(proxy, *token))
    log.Fatal(http.ListenAndServe(":" + strconv.Itoa(*port), nil))
}

 

程序编译:

go build -ldflags "-s -w" go-proxy-pass.go

进一步压缩(可选,需安装upx:https://github.com/upx/upx):

upx -9 go-proxy-pass

 

使用场景:

给 docker REST API 端口添加一层反向代理开启token认证,不想安装 nginx、caddy 等web服务器,只想单文件运行

daemon.json 配置参考:

{
    "hosts":[
        "tcp://127.0.0.1:2375"
    ]
}

  

使用示例:

./go-proxy-pass -port 8375 -proxy_pass http://127.0.0.1:2375

验证:

curl http://127.0.0.1:8375/info

 

使用示例:

./go-proxy-pass -port 8375 -proxy_pass http://127.0.0.1:2375 -token abcdefghijklmnop

验证:

curl -H "token:abcdefghijklmnop" http://127.0.0.1:8375/info

 

posted @ 2022-08-19 17:58  Nihaorz  阅读(210)  评论(0)    收藏  举报