11、Go gin 获取请求IP,nginx配置方案

在使用 Gin 框架时,获取用户请求的真实 IP 地址涉及到多种情况,尤其在使用代理服务器(如 Nginx)时。使用 Gin 自带方法和其他方式获取用户 IP,以及在面对 Nginx 转发时如何准确获取客户端 IP,同时讨论与 IP 相关的安全问题及处理方法。

一、介绍

获取用户的真实 IP 地址是许多应用中必不可少的功能,用于识别用户、记录日志、进行安全控制等。在使用 Gin 框架时,我们需要了解如何正确获取用户的 IP,并处理可能涉及的安全问题。

二、使用 Gin 自带方法获取 IP

 1、 使用 gin.Context 的 ClientIP 方法

Gin 框架提供了 gin.Context 对象的 ClientIP 方法,可直接获取客户端的 IP 地址。 

package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

func getIP(c *gin.Context) {
	ip := c.ClientIP()
	c.JSON(http.StatusOK, gin.H{"ip": ip})
}

func main() {
	router := gin.Default()

	// 手机连电脑同一个局域网可测,即可获取手机网络的IP地址
	router.GET("/getIp", getIP)

	router.Run(":8080")
}

 三、其他方式获取 IP

1、从 http.Request 中获取 

案例一:

实际还是用了gin上下文

package main

import (
	"github.com/gin-gonic/gin"
	"net"
	"net/http"
	"strings"
)

func getIPFromRequest(c *gin.Context) {
	// 获取客户端IP的函数,逻辑与之前相似
	getIP := func(req *http.Request) string {
		xForwardedFor := req.Header.Get("X-Forwarded-For")
		if xForwardedFor != "" {
			ipList := strings.Split(xForwardedFor, ",")
			if len(ipList) > 0 {
				return strings.TrimSpace(ipList[0])
			}
		}

		xRealIP := req.Header.Get("X-Real-IP")
		if xRealIP != "" {
			return xRealIP
		}

		remoteAddr := req.RemoteAddr
		ip, _, err := net.SplitHostPort(remoteAddr)
		if err != nil {
			return remoteAddr
		}
		return ip
	}

	clientIP := getIP(c.Request)
	c.JSON(http.StatusOK, gin.H{"ip": clientIP})
}

func main() {
	router := gin.Default()
	// 手机连电脑同一个局域网可测,即可获取手机网络的IP地址
	router.GET("/getIp", getIPFromRequest)
	router.Run(":8080")
}

 案例二:

使用 X-Real-IP 和 X-Forwarded-For 头部

当应用部署在代理服务器(如 Nginx)后面时,这些服务器通常会添加 X-Real-IP 或 X-Forwarded-For 头部,包含了真实的用户 IP 地址。

package main

import (
	"fmt"
	"net/http"
	"strings"
)

func getClientIP(r *http.Request) string {
	// 尝试从X-Forwarded-For获取
	xForwardedFor := r.Header.Get("X-Forwarded-For")
	if xForwardedFor != "" {
		// 按逗号分割,取第一个IP地址
		ips := strings.Split(xForwardedFor, ",")
		if len(ips) > 0 {
			return strings.TrimSpace(ips[0])
		}
	}

	// 尝试从X-Real-IP获取
	xRealIP := r.Header.Get("X-Real-IP")
	if xRealIP != "" {
		return strings.TrimSpace(xRealIP)
	}

	// 如果以上都没有,使用RemoteAddr
	return r.RemoteAddr
}
func main() {
	http.HandleFunc("/getIp", func(w http.ResponseWriter, r *http.Request) {
		ip := getClientIP(r)
		fmt.Fprint(w, ip)
	})
	http.ListenAndServe(":8080", nil)
}

案例三:

直接从 http.Request 对象中获取客户端 IP 地址,适用于非 Gin 框架的纯 Go 应用。 

package main

import (
	"encoding/json"
	"net/http"
	"strings"
)

// 定义响应结构体
type IPResponse struct {
	IPAddress string `json:"ip"`
}

func getIPFromRequest(w http.ResponseWriter, r *http.Request) {
	// 获取请求的 IP 地址,这里使用了 RemoteAddr 属性,它通常包含了端口号
	ip := strings.Split(r.RemoteAddr, ":")[0]

	// 设置响应的内容类型为 JSON
	w.Header().Set("Content-Type", "application/json")

	// 创建一个 IPResponse 实例并填充 IP 地址
	response := IPResponse{IPAddress: ip}

	// 使用标准库的 json 包将响应结构体编码为 JSON 格式
	if err := json.NewEncoder(w).Encode(response); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func main() {
	// 设置 HTTP 路由处理器
	http.HandleFunc("/getIp", getIPFromRequest)

	// 启动 HTTP 服务器监听 8080 端口
	if err := http.ListenAndServe(":8080", nil); err != nil {
		panic(err)
	}
}

 案例四:

Nginx 转发配置

当应用部署在 Nginx 后面时,需要配置 Nginx 以确保正确传递用户 IP 地址。

# Nginx 配置文件中添加配置
server {
    listen 80;
    server_name your-server-name;

    location / {
        proxy_pass <http://your-gin-app-upstream>;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

 四、安全问题及处理方法

防范 IP 欺骗攻击

问题描述: 攻击者可能伪造请求,冒充其他 IP 地址。

处理方法: 使用防火墙等措施,确保只有可信任的 IP 地址能够访问应用。

防范代理头欺骗

问题描述: 攻击者可能伪造代理头,发送虚假 IP。

处理方法: 在代码中仅信任可靠的代理头,并在获取 IP 前进行相应的验证。 

package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"
)

func getIPWithValidatedProxyHeaders(c *gin.Context) {
	// 获取代理头部
	proxyHeaders := c.Request.Header.Get("X-Real-IP,X-Forwarded-For")

	// 分割代理头部,取第一个 IP 作为真实 IP
	ips := strings.Split(proxyHeaders, ",")
	ip := strings.TrimSpace(ips[0])

	// 如果 IP 格式合法,则使用获取到的 IP,否则使用默认的 ClientIP 方法获取
	if isValidIP(ip) {
		c.JSON(http.StatusOK, gin.H{"ip": ip})
	} else {
		ip = c.ClientIP()
		c.JSON(http.StatusOK, gin.H{"ip": ip})
	}
}

// isValidIP 判断 IP 格式是否合法
func isValidIP(ip string) bool {
	// 此处添加自定义的 IP 格式验证逻辑
	// 例如,使用正则表达式验证 IP 格式
	// ...

	return true
}

func main() {
	router := gin.Default()

	router.GET("/getIp", getIPWithValidatedProxyHeaders)

	router.Run(":8080")
}

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值