How to call API Gateway with Cognito Credentials through retrofit2 on Android?

岁酱吖の 提交于 2019-11-30 07:30:23

Created an OkHttp interceptor based on @thanhbinh84 answer. Give it a try: https://github.com/Ghedeon/AwsInterceptor

It took me several days to figure out how to make it work. Don't know why they don't point out the class instead of dozen of document pages. There are 4 steps in total, you must call in worker thread, I am using Rxjava but you can use AsyncTask instead:

    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) {

            }
        });

The key here is the AWS4Signer class does 4 steps as documented here, you don't need to build one from scratch. In order to use AWS4Signer and AmazonWebServiceRequest, you need to import aws sdk in gradle:

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

The signature process is documented here: http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html

But you could probably try to reuse some of the code from the core runtime package that the default API Gateway client depends on. There may be libraries out there already for signing requests of type RxJava or OkHttp since the signature process is well-known.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!