如何通过Android上的retrofit2使用Cognito Credentials调用API网关?

时间:2016-08-03 07:26:54

标签: android aws-sdk retrofit2 amazon-cognito aws-api-gateway

我在我的Android应用中使用Application.ScreenUpdating = True进行任何http / rest调用。现在我需要调用使用Amazon AWS API Gateway生成的api。

AWS文档say我应该生成客户端代码,抛出API网关控制台并使用类retrofit2来构建请求:

ApiClientFactory

相反,我想像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); 一样定义API:使用我编写的接口,将其连接到RxJava,OkHttp等......

我的问题是:如何使用Cognito Identity Provider签署改装请求?

3 个答案:

答案 0 :(得分:5)

我花了几天时间才弄清楚如何让它发挥作用。不知道为什么他们不指出课程而不是十几个文档页面。总共有4个步骤,你必须在工作线程中调用,我使用Rxjava但你可以使用AsyncTask:

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

            }
        });

这里的关键是AWS4Signer类按照文档here执行4个步骤,您不需要从头开始构建一个。要使用AWS4Signer和AmazonWebServiceRequest,您需要在gradle中导入aws sdk:

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

答案 1 :(得分:3)

基于@ thanhbinh84回答创建了一个OkHttp拦截器。试一试:https://github.com/Ghedeon/AwsInterceptor

答案 2 :(得分:1)

此处记录了签名过程:http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html

但您可能会尝试重用默认API Gateway客户端所依赖的核心运行时包中的一些代码。由于签名过程是众所周知的,因此可能已经存在用于签署RxJava或OkHttp类型请求的库。