升级AWSSDK.Core至3.7.40X.XXX后STS Token生成代码抛空引用异常
升级AWSSDK.Core至3.7.40X版本后CredentialsRetriever触发NullReferenceException的修复方案
问题描述
将AWSSDK.Core包版本从3.7.30X.XXX升级到3.7.40X.XXX后,原有代码在实例化CredentialsRetriever时触发NullReferenceException,报错根源是ServiceMetadata未被正确设置。相同代码在旧版本NuGet包中可正常运行,小版本更新不应出现此类兼容性问题。
原代码报错片段:
// Had to add custom handler - InternalPipelineHandler (it does nothing) but required by RuntimePipeline RuntimePipeline signingPipeline = new RuntimePipeline(new List<IPipelineHandler> { new InternalPipelineHandler(), new Signer(), new EndpointDiscoveryHandler(), new CredentialsRetriever(credentials, // ERROR : NullReferenceException customHeadersHandler, new AmazonSecurityTokenServiceEndpointResolver(), new Marshaller() });
原因分析
在3.7.40X版本的AWSSDK.Core中,CredentialsRetriever的内部构造逻辑发生了变更:旧版本会隐式初始化ServiceMetadata,而新版本中这部分逻辑被移除,直接实例化CredentialsRetriever时如果缺少ServiceMetadata依赖,就会触发空引用异常。
修复方案
方案1:手动初始化ServiceMetadata
在创建ExecutionContext时,显式设置ServiceMetadata,确保CredentialsRetriever能获取到必要的元数据:
var signingContext = new Amazon.Runtime.Internal.ExecutionContext(new RequestContext(false, signer) { ClientConfig = signerParams, Marshaller = GetCallerIdentityRequestMarshaller.Instance, OriginalRequest = new GetCallerIdentityRequest(), IsAsync = false, Options = new InvokeOptions(), // 添加ServiceMetadata初始化 ServiceMetadata = new ServiceMetadata { ServiceId = "STS", EndpointPrefix = "sts" } }, new ResponseContext());
方案2:改用SDK公开API(推荐)
手动构建RuntimePipeline属于SDK内部实现细节,小版本更新容易出现兼容性问题。建议使用官方提供的AmazonSecurityTokenServiceClient来处理签名逻辑,避免依赖内部组件:
var credentials = FallbackCredentialsFactory.GetCredentials(); var awsRegion = RegionEndpoint.GetBySystemName(request.AWSRegion); var config = new AmazonSecurityTokenServiceConfig { StsRegionalEndpoints = StsRegionalEndpointsValue.Regional, RegionEndpoint = awsRegion, AuthenticationServiceName = "sts" }; using var stsClient = new AmazonSecurityTokenServiceClient(credentials, config); // 绑定自定义请求头处理事件 stsClient.BeforeRequestEvent += (sender, args) => { var headers = args.Request.Headers; if (customHeaders != null) { foreach (var header in customHeaders) { headers.Add(header.Key, header.Value.First()); } } // 添加C2C要求的Content-Length头 string REQUEST_BODY = "Action=GetCallerIdentity&Version=2011-06-15"; headers.Add("Content-Length", REQUEST_BODY.Length.ToString()); // 修复Host头格式 var requestEndpoint = args.Request.Endpoint; string host = requestEndpoint.Host; if (!requestEndpoint.IsDefaultPort) { host = $"{host}:{requestEndpoint.Port}"; } headers.Add("Host", host); }; // 执行请求(会自动完成签名流程) var request = new GetCallerIdentityRequest(); stsClient.GetCallerIdentity(request); // 提取签名后的请求信息 var obj = new { headers = stsClient.Config.LastRequestHeaders.ToDictionary(a => a.Key, a => new List<string> { a.Value }), uri = stsClient.Config.LastRequestEndpoint }; var res = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonSerializer.Serialize(obj))); return res;
该方案使用SDK公开的客户端API和事件机制,稳定性更强,后续版本更新时兼容性更有保障。
内容的提问来源于stack exchange,提问作者Tushar Patil
相关产品推荐
相关产品推荐

