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 <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-05-28 13:37:02 +08:00
parent fe81153491
commit c9f7f55d81

View File

@@ -41,8 +41,20 @@ def upload_image(file_bytes: bytes, original_filename: str) -> str:
return object_key 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: def generate_presigned_put_url(object_key: str) -> str:
client = _get_client() client = _get_presign_client()
url: str = client.generate_presigned_url( url: str = client.generate_presigned_url(
"put_object", "put_object",
Params={ Params={
@@ -51,11 +63,4 @@ def generate_presigned_put_url(object_key: str) -> str:
}, },
ExpiresIn=300, 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 return url