You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AwsSignerExecutionAttribute已弃用,如何用AWS Auth SDK签名WebFlux请求?

问题描述

现有一套对Spring WebFlux响应式ClientRequest请求进行签名的逻辑,原代码如下:

import org.springframework.util.MultiValueMapAdapter
import org.springframework.web.reactive.function.client.ClientRequest
import reactor.core.publisher.Mono
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider
import software.amazon.awssdk.auth.signer.Aws4Signer
import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute
import software.amazon.awssdk.core.interceptor.ExecutionAttributes
import software.amazon.awssdk.http.SdkHttpFullRequest
import software.amazon.awssdk.http.SdkHttpMethod
import software.amazon.awssdk.regions.Region
import java.util.function.Function

class WebClientAwsSigner(
    private val body: String? = null,
    private val signer: Aws4Signer,
    private val awsCredentialsProvider: AwsCredentialsProvider,
    private val serviceName: String,
    private val region: Region
) : Function<ClientRequest, Mono<ClientRequest>> {
    override fun apply(request: ClientRequest): Mono<ClientRequest> {
        val requestBuilder =
            SdkHttpFullRequest.builder()
                .method(SdkHttpMethod.fromValue(request.method().name()))
                .uri(request.url())
                .apply {
                    if (body != null) {
                        contentStreamProvider { body.byteInputStream() }
                    }
                }
                .headers(request.headers())

        val attributes = ExecutionAttributes()
        attributes.putAttribute(
            AwsSignerExecutionAttribute.AWS_CREDENTIALS,
            awsCredentialsProvider.resolveCredentials()
        )
        attributes.putAttribute(AwsSignerExecutionAttribute.SERVICE_SIGNING_NAME, serviceName)
        attributes.putAttribute(AwsSignerExecutionAttribute.SIGNING_REGION, region)

        val signedAwsRequest = signer.sign(requestBuilder.build(), attributes)
        val signedClientRequest =
            ClientRequest.from(request)
                .headers {
                    it.clear()
                    it.addAll(MultiValueMapAdapter(signedAwsRequest.headers()))
                }
                .build()

        return Mono.just(signedClientRequest)
    }
}

但其中AwsSignerExecutionAttribute已被弃用,需要调整为AWS Auth SDK的当前推荐用法,同时保持对响应式ClientRequest的签名支持。

解决方案

AWS SDK v2中,Aws4Signer的签名逻辑已更新,不再依赖ExecutionAttributes传递签名参数,而是使用Aws4SignerParams封装必要的签名信息。以下是修改后的代码:

import org.springframework.util.MultiValueMapAdapter
import org.springframework.web.reactive.function.client.ClientRequest
import reactor.core.publisher.Mono
import software.amazon.awssdk.auth.credentials.AwsCredentials
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider
import software.amazon.awssdk.auth.signer.Aws4Signer
import software.amazon.awssdk.auth.signer.Aws4SignerParams
import software.amazon.awssdk.http.SdkHttpFullRequest
import software.amazon.awssdk.http.SdkHttpMethod
import software.amazon.awssdk.regions.Region
import java.time.Instant
import java.util.function.Function

class WebClientAwsSigner(
    private val body: String? = null,
    private val signer: Aws4Signer,
    private val awsCredentialsProvider: AwsCredentialsProvider,
    private val serviceName: String,
    private val region: Region
) : Function<ClientRequest, Mono<ClientRequest>> {

    override fun apply(request: ClientRequest): Mono<ClientRequest> {
        // 构建SDK HTTP请求对象
        val sdkRequest = SdkHttpFullRequest.builder()
            .method(SdkHttpMethod.fromValue(request.method().name()))
            .uri(request.url())
            .apply {
                body?.let { contentStreamProvider { it.byteInputStream() } }
            }
            .headers(request.headers())
            .build()

        // 获取AWS凭证
        val credentials: AwsCredentials = awsCredentialsProvider.resolveCredentials()

        // 构建签名参数
        val signerParams = Aws4SignerParams.builder()
            .credentials(credentials)
            .signingName(serviceName)
            .signingRegion(region)
            .signingClockOverride(Instant.now()) // 可选:指定签名时间,默认用系统时间
            .build()

        // 执行签名
        val signedSdkRequest = signer.sign(sdkRequest, signerParams)

        // 将签名后的头部映射回ClientRequest
        val signedClientRequest = ClientRequest.from(request)
            .headers { headers ->
                headers.clear()
                headers.addAll(MultiValueMapAdapter(signedSdkRequest.headers()))
            }
            .build()

        return Mono.just(signedClientRequest)
    }
}

关键变化说明

  • 替换弃用的ExecutionAttributes:改用Aws4SignerParams封装签名所需的凭证、服务名、区域等参数,这是当前AWS SDK推荐的方式。
  • 直接传递签名参数:不再通过属性键隐式传递信息,而是通过Aws4SignerParams.Builder明确配置各项参数,代码可读性更强。
  • 签名时间处理:可通过signingClockOverride指定签名使用的时间,默认使用系统当前时间,通常无需额外配置。
  • 保持响应式兼容:逻辑依然返回Mono<ClientRequest>,完美适配Spring WebFlux的响应式调用链。

额外注意事项

  • 确保使用的AWS SDK版本在2.17.0及以上(Aws4SignerParams在此版本引入)。
  • 如果请求体是动态生成的,需确保签名前能获取完整的请求体内容,因为AWS签名需要计算请求体哈希。
  • 若需异步获取凭证,可将凭证解析逻辑改为响应式调用,适配异步场景:
override fun apply(request: ClientRequest): Mono<ClientRequest> {
    val sdkRequest = SdkHttpFullRequest.builder()
        .method(SdkHttpMethod.fromValue(request.method().name()))
        .uri(request.url())
        .apply {
            body?.let { contentStreamProvider { it.byteInputStream() } }
        }
        .headers(request.headers())
        .build()

    return Mono.fromCallable { awsCredentialsProvider.resolveCredentials() }
        .map { credentials ->
            val signerParams = Aws4SignerParams.builder()
                .credentials(credentials)
                .signingName(serviceName)
                .signingRegion(region)
                .build()
            signer.sign(sdkRequest, signerParams)
        }
        .map { signedSdkRequest ->
            ClientRequest.from(request)
                .headers { headers ->
                    headers.clear()
                    headers.addAll(MultiValueMapAdapter(signedSdkRequest.headers()))
                }
                .build()
        }
}

内容的提问来源于stack exchange,提问作者pixel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 00:36:11