You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Gin框架时能否让GET请求无需MTLS校验其余请求启用MTLS防护

基于Gin实现路由组级别的mTLS校验方案

TLS握手逻辑发生在HTTP请求路由匹配之前,因此无法直接为不同Gin路由组绑定独立的TLS配置。我们可以通过调整服务端TLS策略+自定义中间件的方式实现需求:先将服务端配置为「请求但不强制校验客户端证书」,再通过Gin中间件仅对需要防护的路由组做mTLS校验。

具体实现步骤

  • 调整HTTP服务的TLS配置,将ClientAuth字段设置为tls.RequestClientCert,服务端会主动请求客户端证书,但不会直接拒绝未携带证书的请求
  • 实现mTLS校验中间件,逻辑为校验请求携带的客户端证书是否被信任的CA根证书池认可,校验不通过直接返回错误响应
  • 将校验中间件挂载到需要mTLS保护的私有路由组,公开路由组无需挂载该中间件

修改后的完整代码

package main

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"

	"log"

	"github.com/gin-gonic/gin"
)

// mTLS校验中间件
func mtlsAuthMiddleware(rootCAs *x509.CertPool) gin.HandlerFunc {
	return func(c *gin.Context) {
		// 检查是否携带客户端证书
		if len(c.Request.TLS.PeerCertificates) == 0 {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "需提供客户端证书"})
			return
		}
		// 校验客户端证书有效性
		clientCert := c.Request.TLS.PeerCertificates[0]
		verifyOpts := x509.VerifyOptions{
			Roots: rootCAs,
		}
		if _, err := clientCert.Verify(verifyOpts); err != nil {
			c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "客户端证书无效"})
			return
		}
		c.Next()
	}
}

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

	// 无需mTLS校验的公开路由组
	public := router.Group("/")
	// 需要mTLS校验的私有路由组
	private := router.Group("/")

	public.GET("/insecure-ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "insecure pong",
		})
	})

	private.POST("/secure-ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "secure pong",
		})
	})

	// 初始化信任的CA根证书池
	rootCAs, err := x509.SystemCertPool()
	if err != nil {
		log.Fatal(err)
	}
	if rootCAs == nil {
		rootCAs = x509.NewCertPool()
	}

	caCert, err := ioutil.ReadFile("cacert.pem")
	if err != nil {
		log.Fatal(err)
	}

	if ok := rootCAs.AppendCertsFromPEM(caCert); !ok {
		err := errors.New("添加CA证书到系统信任池失败")
		log.Fatal(err)
	}

	// 私有路由组挂载mTLS校验中间件
	private.Use(mtlsAuthMiddleware(rootCAs))

	server := http.Server{
		Addr:    fmt.Sprintf(":%v", 8080),
		Handler: router,
		TLSConfig: &tls.Config{
			RootCAs:    rootCAs,
			ClientAuth: tls.RequestClientCert, // 关键配置:请求但不强制校验客户端证书
		},
	}

	err = server.ListenAndServeTLS("certificate.crt", "privateKey.key")
	if err != nil {
		log.Fatal(err)
	}
}

内容的提问来源于stack exchange,提问作者James

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 13:24:02