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

如何在ogen SecurityHandler中获取原始请求体?

问题解答

核心结论

直接通过ogen的SecurityHandler接口无法获取原始请求体——该接口的设计仅聚焦于认证凭据(如API Key)的校验,并未暴露原始请求或请求体的访问途径。不过可以通过中间件+上下文传递的变通方案,在SecurityHandler中拿到原始请求体,无需完全放弃SecurityHandler的使用。

可行实现方案

1. 编写中间件存储原始请求体

先实现一个HTTP中间件,读取并保存原始请求体到请求上下文(Context)中,同时要将请求体写回,避免后续ogen解析请求时失败:

import (
    "bytes"
    "context"
    "io"
    "net/http"
    "errors"
)

// 自定义Context Key,用于存储原始请求体
const rawRequestBodyKey = "rawRequestBody"

func RequestBodyMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // 读取原始请求体
        rawBody, err := io.ReadAll(r.Body)
        if err != nil {
            http.Error(w, "failed to read request body", http.StatusBadRequest)
            return
        }
        // 将请求体写回,保证后续流程可正常读取
        r.Body = io.NopCloser(bytes.NewBuffer(rawBody))
        // 将原始请求体存入Context
        ctx := context.WithValue(r.Context(), rawRequestBodyKey, rawBody)
        // 传递处理后的请求
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

2. 在SecurityHandler中读取请求体

修改你的SecurityHandler.Handle方法,从Context中取出预先存储的原始请求体,用于Webhook验证:

func (s SecurityHandler) Handle(ctx context.Context, operationName string, t gen.APIHeader) (context.Context, error) {
    if !m.env.Application.LocalMode {
        // 从Context中获取原始请求体
        rawBody, ok := ctx.Value(rawRequestBodyKey).([]byte)
        if !ok {
            return ctx, errors.New("missing raw request body in context")
        }
        // 传入原始请求体完成Webhook验证
        if err := VerifyWebhook(t.APIKey, rawBody, SECRET_KEY); err != nil {
            return ctx, err
        }
    }
    return ctx, nil
}

3. 挂载中间件到ogen处理器

将上述中间件挂载到ogen生成的API处理器之前,确保请求先经过中间件处理:

// 假设apiHandler是ogen生成的HTTP处理器
http.Handle("/api/", RequestBodyMiddleware(apiHandler))

替代方案:直接用中间件完成验证

如果不需要依赖SecurityHandler,也可以直接在中间件中完成API Key校验和请求体验证逻辑,跳过SecurityHandler的使用:

func WebhookAuthMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if !m.env.Application.LocalMode {
            // 提取API Key
            apiKey := r.Header.Get("X-API-Key") // 根据你的Header名称调整
            if apiKey == "" {
                http.Error(w, "missing API key", http.StatusUnauthorized)
                return
            }
            // 读取原始请求体
            rawBody, err := io.ReadAll(r.Body)
            if err != nil {
                http.Error(w, "failed to read request body", http.StatusBadRequest)
                return
            }
            r.Body = io.NopCloser(bytes.NewBuffer(rawBody))
            // 执行Webhook验证
            if err := VerifyWebhook(apiKey, rawBody, SECRET_KEY); err != nil {
                http.Error(w, err.Error(), http.StatusUnauthorized)
                return
            }
        }
        next.ServeHTTP(w, r)
    })
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 00:33:34