fix(encrypt): 全量加密豁免 multipart 上传,修复文件上传被拒
问题:encrypt.fullBody=true 时,APICrypto 中间件会把所有非豁免请求的
body 当 JSON 解析取 {encryptedKey, encryptedData}。文件上传走
multipart/form-data,body 是二进制流,json.Unmarshal 必然失败,于是
被判定为「未加密的业务请求」直接拒绝(encrypted request required)。
而前端的请求拦截器对 FormData 是一律跳过加密的
(admin request.ts:`config.data instanceof FormData` 直接 return),
即上传请求本就以明文 multipart 发出。两端语义不一致,导致
fullBody 一开启,后台壁纸上传必然报错。
修复:新增 isMultipartRequest 判断,命中 multipart/form-data 的请求
跳过整体解密;响应侧因拿不到会话密钥(aesKeyB64 为空),保持明文
回传,与前端「FormData 请求不解密响应」的行为对齐。
dev 环境 fullBody=false,该路径不会被触发,故此前联调未暴露。
上传接口仍受 JWT 鉴权与 RBAC(POST + path 精确匹配)保护,豁免
整体加密不降低鉴权强度。
This commit is contained in:
parent
a337336a50
commit
d136c23874
@ -42,6 +42,20 @@ func isPlainRoute(r *ghttp.Request) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// isMultipartRequest 判断是否为 multipart/form-data 请求(文件上传)。
|
||||
//
|
||||
// 必须豁免的原因:上传体是二进制文件流,无法整体做 JSON 加解密;前端的
|
||||
// 请求拦截器对 FormData 一律跳过加密(见 admin 的 request.ts:
|
||||
// `config.data instanceof FormData` 直接 return),两端必须保持一致,
|
||||
// 否则上传会被当成「未加密的业务请求」直接拒绝,
|
||||
// 表现为「选了文件、点了上传,报 encrypted request required」。
|
||||
//
|
||||
// 豁免不影响安全:上传接口同样挂在 /api/service/admin 分组下,
|
||||
// 仍受 JWT 鉴权与 RBAC 菜单权限(POST + path 精确匹配)双重保护。
|
||||
func isMultipartRequest(r *ghttp.Request) bool {
|
||||
return gstr.Contains(r.Header.Get("Content-Type"), "multipart/form-data")
|
||||
}
|
||||
|
||||
// APICrypto 全量请求/响应加密中间件。
|
||||
// 必须注册在 ghttp.MiddlewareHandlerResponse 外层(先于其执行),
|
||||
// 且建议置于 Recover 外层,使 500 等异常响应同样被加密。
|
||||
@ -49,7 +63,9 @@ func isPlainRoute(r *ghttp.Request) bool {
|
||||
func APICrypto(svc *cryptolib.Service) ghttp.HandlerFunc {
|
||||
return func(r *ghttp.Request) {
|
||||
// ---- 请求解密 ----
|
||||
if svc.FullBody() && !isPlainRoute(r) {
|
||||
// multipart/form-data(文件上传)整体豁免:二进制流无法 JSON 加密,
|
||||
// 前端对 FormData 同样跳过加密,此处必须同步放行。
|
||||
if svc.FullBody() && !isPlainRoute(r) && !isMultipartRequest(r) {
|
||||
// 直接读原始 body(勿用 r.GetBody():会缓存密文到 bodyContent,
|
||||
// 而 handler 的 Parse 走 GetBody 缓存,导致收到密文而非解密后的明文)。
|
||||
body, _ := io.ReadAll(r.Request.Body)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user