如何在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
相关产品推荐
相关产品推荐

