使用 API 网关的 Amazon Cognito 身份

Amazon Cognito Identity with API Gateway

我正在使用 Xamarin 跨平台开发应用 IOS 和 Android。 我正在努力使用从 Cognito Identity 接收的凭据来授权应用程序调用 API 网关。

我的用户流是:

  1. 在 Cognito 用户池上进行身份验证并获取令牌
  2. 在 Cognito 身份池上用令牌交换凭据
  3. 使用在上一步中检索到的凭据访问 API 网关。

第 1 步和第 2 步似乎工作正常。但是当应用程序尝试连接到 api 网关时,它收到错误 403(禁止访问)。

我的代码:

  1. 在 Cognito 用户池上进行身份验证并获取令牌

**

public async Task<AppUser> Login(string username, string password)   
 {
        CognitoUser cognitoUser = new CognitoUser(username, Aws.COGNITO_CLIENT_ID, CognitoUserPool, CognitoIdentityProviderClient);
        AppUser appUser = new AppUser() { Email = username };
        // Send a login request and wait for the response from Amazon
        try
        {
            AuthFlowResponse response = await cognitoUser.StartWithSrpAuthAsync(new InitiateSrpAuthRequest()
            {                    
                Password = password
            });
            ;
            appUser.IsAuthenticated = true;
        }
        catch (NotAuthorizedException e)
        {
            appUser.IsAuthenticated = false;
            appUser.ErrorMessage = e.Message;
        }
        await _tokenManagement.SaveTokens(cognitoUser.SessionTokens) ;
        return appUser;
    }
  1. 在 Cognito 身份池上用令牌交换凭据

**

public async Task<ImmutableCredentials> GetAppCredentialsAsync()
{
    CognitoAWSCredentials cac;
        
        if (_tokenManagement.CheckIsAnonymous())
        {
            //Anonymous credentials        
            cac = new CognitoAWSCredentials(Aws.COGINITO_IDENTITY_POLL_ID, RegionEndpoint.USEast1); 
        }
        else
        {
            //Retrieve saved tokens from previous authentication
            var tm = await _tokenManagement.RetrieveTokens();
        
            CognitoUser user = new CognitoUser(null, Aws.COGNITO_CLIENT_ID, CognitoUserPool, CognitoIdentityProviderClient)
            {
                    SessionTokens = new CognitoUserSession(tm.IdToken, tm.AccessToken, tm.RefreshToken, tm.IssuedTime, tm.ExpirationTime)
            };
            //Retrieve authenticated credentials
            cac = user.GetCognitoAWSCredentials(Aws.COGINITO_IDENTITY_POLL_ID, RegionEndpoint.USEast1);
        
        }
                       
     }
                 
    return await cac.GetCredentialsAsync();
        
}
  1. 使用在上一步中检索到的凭据访问 API 网关:

**

public async Task<IList<MediaImage>> GetCoversAWSAsync()
    {
        // Getting credentials and sign request
        var request = await BuildRequestAsync("/listMedia");
        
        var client = new HttpClient();
        
        var response = await client.SendAsync(request);
        response.EnsureSuccessStatusCode();
    
        IList<MediaImage> covers = JsonConvert.DeserializeObject<IList<MediaImage>>(await response.Content.ReadAsStringAsync());
    
        return covers;
    
    }
    
    private async Task<HttpRequestMessage> BuildRequestAsync(string service)
    {
    
        var request = new HttpRequestMessage()
        {
            Method = HttpMethod.Get,
            RequestUri = new Uri(baseURL + service)
            
        };   
        
        ImmutableCredentials awsCredential = await _loginService.GetAppCredentialsAsync( );
                       
    
        var signer = new AWS4RequestSigner(awsCredential.AccessKey, awsCredential.SecretKey);
    
        request = await signer.Sign(request, "execute-api", awsRegion);
    
    
        return request;
    
    }

当我对来自一个 IAM 用户的凭据进行硬编码时,此代码工作正常。但是从 Cognito Identities 检索到的凭据出现 Forbidden 错误。 我使用适用于 S3 的 SDK 进行了测试,我能够使用从 Cognito Identities 收到的相同凭据成功列出存储桶,但无法在 API 网关上发出请求。

你能帮帮我吗?我在哪里迷路了?

我弄明白是怎么回事了。

确保 AWS 上的权限设置正确后。

我在文档中发现有必要在 HTTP header 中包含 cognito(header 名称 x-amz-security-token)返回的令牌。所以我将代码更改为以下内容:

    private async Task<HttpRequestMessage> BuildRequestAsync(string service)
    {
    
        var request = new HttpRequestMessage()
        {
            Method = HttpMethod.Get,
            RequestUri = new Uri(baseURL + service)
            
        };   
        
        ImmutableCredentials awsCredential = await _loginService.GetAppCredentialsAsync( );

        //This where I add header to the HTTP request              
        request.Headers.Add("x-amz-security-token", awsCredential.Token);

        var signer = new AWS4RequestSigner(awsCredential.AccessKey, awsCredential.SecretKey);
    
        request = await signer.Sign(request, "execute-api", awsRegion);
    
    
        return request;
    
    }