gin 自己实现csrf令牌


go
import (
	"crypto/rand"
	"encoding/base64"
	"github.com/gin-gonic/gin"
)

// 生成 CSRF Token,并将其保存在上下文中
func setCSRFToken() gin.HandlerFunc {
	return func(c *gin.Context) {
		b := make([]byte, 32)
		rand.Read(b)
		csrfToken := base64.StdEncoding.EncodeToString(b)
		c.Set("csrfToken", csrfToken)
		// 有效期为 1 小时
		c.SetCookie("csrf_token", csrfToken, 3600, "/", "", false, true)
	}
}

// 验证 CSRF Token,注意,在前端只有同时在请求头和cookie中都有才安全
func valiCSRFToken() gin.HandlerFunc {
	return func(c *gin.Context) { 
        // 从请求中获取 CSRF 令牌
        csrfToken := c.GetHeader("X-CSRF-Token")
        // 从 Cookie 中获取 CSRF 令牌
        cookie, err := c.Cookie("csrf_token")
		if err != nil {
			c.JSON(403, gin.H{"msg": "CSRF令牌无效或过期,请刷新页面重新提交"})
			c.Abort()
			return
		}

		// 验证 CSRF 令牌
        if csrfToken != cookie {
            c.JSON(403, gin.H{"msg": "CSRF 令牌无效"})
            c.Abort()
            return
        }
		c.Next()
	}
}

// 假设这是路由函数中
// 路由中使用令牌中间件
r.GET("/login",setCSRFToken(), view.Login)
r.POST("/login",valiCSRFToken(), view.Login)


//假设这是get视图函数中
// 读取csrf token
csrfToken, _ := c.Get("csrfToken")
c.HTML(200, "login.html", gin.H{"title": "登陆","csrfToken":csrfToken})

前端模板中使用令牌

js
// 发送 POST 请求
await axios.post('/'+ff, this.form,{
headers: {
  'X-CSRF-Token': {{.csrfToken}} 
}
})
.then((res) => {
//跳转到首页
window.location.href = '/';
})
.catch(err => {
this.msg = err.response.data.msg;
// 刷新验证码
this.aptchaSrc = "/api/imgcaptcha?" + Math.random();
});