mirror of
https://github.com/zeromicro/go-zero.git
synced 2026-05-13 18:00:00 +08:00
Fix JWT middleware to skip body dump for multipart/form-data requests
Co-authored-by: kevwan <1918356+kevwan@users.noreply.github.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
"github.com/zeromicro/go-zero/core/logc"
|
"github.com/zeromicro/go-zero/core/logc"
|
||||||
@@ -99,10 +100,17 @@ func WithUnauthorizedCallback(callback UnauthorizedCallback) AuthorizeOption {
|
|||||||
|
|
||||||
func detailAuthLog(r *http.Request, reason string) {
|
func detailAuthLog(r *http.Request, reason string) {
|
||||||
// discard dump error, only for debug purpose
|
// discard dump error, only for debug purpose
|
||||||
details, _ := httputil.DumpRequest(r, true)
|
// Skip dumping request body for multipart/form-data to avoid reading large files
|
||||||
|
dumpBody := !isMultipartFormData(r)
|
||||||
|
details, _ := httputil.DumpRequest(r, dumpBody)
|
||||||
logc.Errorf(r.Context(), "authorize failed: %s\n=> %+v", reason, string(details))
|
logc.Errorf(r.Context(), "authorize failed: %s\n=> %+v", reason, string(details))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isMultipartFormData(r *http.Request) bool {
|
||||||
|
contentType := r.Header.Get("Content-Type")
|
||||||
|
return strings.Contains(contentType, "multipart/form-data")
|
||||||
|
}
|
||||||
|
|
||||||
func unauthorized(w http.ResponseWriter, r *http.Request, err error, callback UnauthorizedCallback) {
|
func unauthorized(w http.ResponseWriter, r *http.Request, err error, callback UnauthorizedCallback) {
|
||||||
writer := response.NewHeaderOnceResponseWriter(w)
|
writer := response.NewHeaderOnceResponseWriter(w)
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,72 @@ func TestAuthHandler_NilError(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAuthHandlerWithMultipartFormData(t *testing.T) {
|
||||||
|
const key = "B63F477D-BBA3-4E52-96D3-C0034C27694A"
|
||||||
|
|
||||||
|
// Create a multipart form-data request
|
||||||
|
// We don't need actual body content since we're testing that
|
||||||
|
// the body is NOT read when Content-Type is multipart/form-data
|
||||||
|
req := httptest.NewRequest(http.MethodPost, "http://localhost/upload",
|
||||||
|
http.NoBody)
|
||||||
|
req.Header.Set("Content-Type", "multipart/form-data; boundary=----WebKitFormBoundary")
|
||||||
|
// Missing authorization header to trigger the unauthorized path
|
||||||
|
|
||||||
|
handler := Authorize(key)(
|
||||||
|
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}))
|
||||||
|
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
handler.ServeHTTP(resp, req)
|
||||||
|
|
||||||
|
// Should return unauthorized
|
||||||
|
assert.Equal(t, http.StatusUnauthorized, resp.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsMultipartFormData(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
contentType string
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "multipart/form-data",
|
||||||
|
contentType: "multipart/form-data",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multipart/form-data with boundary",
|
||||||
|
contentType: "multipart/form-data; boundary=----WebKitFormBoundary",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "application/json",
|
||||||
|
contentType: "application/json",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "application/x-www-form-urlencoded",
|
||||||
|
contentType: "application/x-www-form-urlencoded",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty content type",
|
||||||
|
contentType: "",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
req := httptest.NewRequest(http.MethodPost, "http://localhost", http.NoBody)
|
||||||
|
req.Header.Set("Content-Type", tt.contentType)
|
||||||
|
result := isMultipartFormData(req)
|
||||||
|
assert.Equal(t, tt.expected, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func buildToken(secretKey string, payloads map[string]any, seconds int64) (string, error) {
|
func buildToken(secretKey string, payloads map[string]any, seconds int64) (string, error) {
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
claims := make(jwt.MapClaims)
|
claims := make(jwt.MapClaims)
|
||||||
|
|||||||
Reference in New Issue
Block a user