6 votes

Comment appeler API Gateway avec Cognito Credentials via retrofit2 sur Android ?

J'utilise retrofit2 dans mes applications Android pour tout appel http/rest. Maintenant j'ai besoin d'appeler une api générée avec Passerelle API d'Amazon AWS .

La documentation AWS dire Je devrais générer le code client en lançant la console API Gateway et utiliser la classe ApiClientFactory pour élaborer la demande :

ApiClientFactory factory = new ApiClientFactory();

// Use CognitoCachingCredentialsProvider to provide AWS credentials
// for the ApiClientFactory
AWSCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
        context,          // activity context
        "identityPoolId", // Cognito identity pool id
        Regions.US_EAST_1 // region of Cognito identity pool
};

factory.credentialsProvider(credentialsProvider);

// Create an instance of your SDK (this should come from the generated code).
final MyApiClient client = factory.build(MyApiClient.class);

// Invoke a method (e.g., 'parentPath1Get(param1,body)') exposed by your SDK. 
// Here the method's return type is OriginalModel.
OriginalModel output = client.parentPath1Get(param1,body);

// You also have access to your API's models.
OriginalModel myModel = new OriginalModel();
myModel.setStreetAddress(streetAddress);
myModel.setCity(city);
myModel.setState(state);
myModel.setStreetNumber(streetNumber);
myModel.setNested(nested);
myModel.setPoBox(poBox);

Au lieu de cela, j'aimerais définir l'API comme je le ferais avec retrofit : avec une interface que j'écris, la connecter à RxJava, OkHttp etc...

Ma question est la suivante : comment puis-je signer les demandes de rétrofit avec Cognito Identity Provider ?

5voto

doraemon Points 4099

Il m'a fallu plusieurs jours pour comprendre comment le faire fonctionner. Je ne sais pas pourquoi ils n'indiquent pas la classe au lieu d'une douzaine de pages de documents. Il y a 4 étapes au total, vous devez appeler dans un thread de travailleur, j'utilise Rxjava mais vous pouvez utiliser AsyncTask à la place :

    Observable.create((Observable.OnSubscribe<String>) subscriber -> {
//Step 1: Get credential, ask server team for Identity pool id and regions            
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
                this, // Context
                "Identity Pool ID", // Identity Pool ID
                Regions.US_EAST_1 // Region
            );

//Step 2: Get these 3 three keys, test with postman v4.9.3 to see if identity is correct  
            String identityId = credentialsProvider.getIdentityId();
            Log.show("identityId = " + identityId);

            String AccessKey = credentialsProvider.getCredentials().getAWSAccessKeyId();
            String SecretKey = credentialsProvider.getCredentials().getAWSSecretKey();
            String SessionKey = credentialsProvider.getCredentials().getSessionToken();

            Log.show("AccessKey = " + AccessKey);
            Log.show("SecretKey = " + SecretKey);
            Log.show("SessionKey = " + SessionKey);
//Step 3: Create an aws requets and sign by using AWS4Signer class
            AmazonWebServiceRequest amazonWebServiceRequest = new AmazonWebServiceRequest() {
            };

            ClientConfiguration clientConfiguration = new ClientConfiguration();

            String API_GATEWAY_SERVICE_NAME = "execute-api";

            Request request = new DefaultRequest(amazonWebServiceRequest,API_GATEWAY_SERVICE_NAME);
            request.setEndpoint(URI.create("YOUR_URI"));
            request.setHttpMethod(HttpMethodName.GET);

            AWS4Signer signer = new AWS4Signer();
            signer.setServiceName(API_GATEWAY_SERVICE_NAME);
            signer.setRegionName(Region.getRegion(Regions.US_EAST_1).getName());
            signer.sign(request, credentialsProvider.getCredentials());

            Log.show("Request header " + request.getHeaders().toString());
//Step 4: Create new request with authorization headers 

            OkHttpClient httpClient = new OkHttpClient();
            Map<String, String> headers = request.getHeaders();
            List<String> key = new ArrayList<String>();
            List<String> value = new ArrayList<String>();

            for (Map.Entry<String, String> entry : headers.entrySet())
            {
                key.add(entry.getKey());
                value.add(entry.getValue());
            }

            try {
                okhttp3.Request request2 = new okhttp3.Request.Builder()
                        .url("Your_url") // remember to add / to the end of the url, otherwise the signature will be different 
                        .addHeader(key.get(0), value.get(0))
                        .addHeader(key.get(1), value.get(1))
                        .addHeader(key.get(2), value.get(2))
                        .addHeader(key.get(3), value.get(3))

                        .addHeader("Content-Type", "application/x-www-form-urlencoded")
                        .build();
                Response response = null;

                response = httpClient.newCall(request2).execute();
                String body = response.body().string();
                Log.show("response " + body);
            } catch (Exception e) {
                Log.show("error " + e);
            }

            subscriber.onNext(identityId);

        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<String>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                Log.show("Throwable = " + e.getMessage());
            }

            @Override
            public void onNext(String s) {

            }
        });

La clé ici est que la classe AWS4Signer effectue 4 étapes comme indiqué dans la documentation ici Il n'est pas nécessaire d'en construire un à partir de zéro. Afin d'utiliser AWS4Signer et AmazonWebServiceRequest, vous devez importer aws sdk dans gradle :

compile 'com.amazonaws:aws-android-sdk-cognito:2.3.9'

2voto

Ghedeon Points 564

Création d'un intercepteur OkHttp basé sur la réponse de @thanhbinh84. Essayez-le : https://github.com/Ghedeon/AwsInterceptor

1voto

Jack Kohn - AWS Points 4593

La procédure de signature est documentée ici : http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html

Mais vous pouvez probablement essayer de réutiliser une partie du code du paquetage d'exécution de base dont dépend le client API Gateway par défaut. Il existe peut-être déjà des bibliothèques permettant de signer les demandes de type RxJava ou OkHttp, puisque le processus de signature est bien connu.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X