From c9f7f55d81022843049ba9674cb315a5d48e1e95 Mon Sep 17 00:00:00 2001 From: Misaka_Company Date: Thu, 28 May 2026 13:37:02 +0800 Subject: [PATCH] Fix presigned URL: use public endpoint for signature generation Host replacement broke S3 signatures since host is a signed header. Instead, create a separate boto3 client with public_endpoint for presign. Co-Authored-By: Claude Opus 4.6 --- app/services/minio.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/app/services/minio.py b/app/services/minio.py index dc8cf5a..e16e0bc 100644 --- a/app/services/minio.py +++ b/app/services/minio.py @@ -41,8 +41,20 @@ def upload_image(file_bytes: bytes, original_filename: str) -> str: return object_key +def _get_presign_client(): + """Client using public endpoint so presigned URL signatures match the public host.""" + endpoint = settings.minio.public_endpoint or settings.minio.endpoint + return boto3.client( + "s3", + endpoint_url=endpoint, + aws_access_key_id=settings.minio.access_key, + aws_secret_access_key=settings.minio.secret_key, + config=BotoConfig(signature_version="s3v4"), + ) + + def generate_presigned_put_url(object_key: str) -> str: - client = _get_client() + client = _get_presign_client() url: str = client.generate_presigned_url( "put_object", Params={ @@ -51,11 +63,4 @@ def generate_presigned_put_url(object_key: str) -> str: }, ExpiresIn=300, ) - # Replace internal endpoint with public endpoint - if settings.minio.public_endpoint: - from urllib.parse import urlparse, urlunparse - - internal = urlparse(settings.minio.endpoint) - public = urlparse(settings.minio.public_endpoint) - url = url.replace(f"{internal.scheme}://{internal.netloc}", f"{public.scheme}://{public.netloc}", 1) return url