亚马逊AWS官方博客

Amazon Cognito 集成微信登录部署系列(五)客户端集成 Cognito 验证

在上一篇中我们实现了对接微信开放平台验证微信用户的业务逻辑,并调试通了Lambda函数和API Gateway。在本篇中,我们将最终完成Android客户端,实现授权并访问AWS资源。

API Gateway部署 API

最后我们把这个 API 发布出来。在API控制台点击操作按钮,选择部署API,首次部署,我们在部署阶段下拉菜单选择[新阶段],阶段名称输入“test”,点击部署按钮即可。然后会跳转到“test 阶段编辑器”。可以看到显示调用 URL类似 https://1234567890---execute-api---cn-north-1.amazonaws.com.rproxy.goskope.com.cn/test。因为这个方法是 POST方式提交,所以我们可以用curl命令行方式测试一下。

$ curl -d'{"code":"001YYVIG19Qt700dmWHG1nDUIG1YYVI7"}' 'https://1234567890---execute-api---cn-north-1.amazonaws.com.rproxy.goskope.com.cn/test/loginwechat'

{"identityId":"cn-north-1:12345678-1234-4ba8-a97f-19948a5e422a","userId":123,"openIdToken":"eyJraWQiOiJjbi1ub3J0aC0xMiIsInR5cCI6IkpXUyIsImFsZyI6IlJTNTEyIn0.eyJzdWIiOiJjbi1ub3J0aC0xOmQ0YzIxZDkwLWE2YjEtNGJhOC1hOTdmLTE5OTQ4YTVlNDIyYSIsImF1ZCI6ImNuLW5vcnRoLTE6Y2M3YTQ0NWEtNWZhMS00OGM4LTkwYmUtNDAyYjI1ZmRlMDViIiwiYW1yIjpbImF1dGhlbnRpY2F0ZWQiLCJjbi5hd3MuY29nbml0b3dlY2hhdCIsImNuLmF3cy5jb2duaXRvd2VjaGF0OmNuLW5vcnRoLTE6Y2M3YTQ0NWEtNWZhMS00OGM4LTkwYmUtNDAyYjI1ZmRlMDViOjEyMyJdLCJpc3MiOiJodHRwczovL2NvZ25pdG8taWRlbnRpdHkuY24tbm9ydGgtMS5hbWF6b25hd3MuY29tLmNuIiwiZXhwIjoxNTQ2MDc2NzM1LCJpYXQiOjE1NDYwNjY3MzR9.RTKre1SvI-NMKBwsfV0J2Z6WF0YVE1WdUhbzu_lPFmrtYbG__wC93zmR5OnpFouJHgeKBJC4abhvdxYltUdy7ltuK9YjHNDVVjx9IDdnLOt2kG3BUkzNQOAx9neyWOhomGM_XeiaaIbAR6EeMjTIMxl2Lyz13sFwuYSeulgBCeSDew27O-a0KNRLu2NVhOMA8-sZiXYVpdu5XqRMtJrC4FyResxTfeAS-arjrbc-A3NR_-70FCLze-Aaz9Bz0UeC7rskDvAdih-zDqxSh7LzdZz7lK4TS6AHui22fOFKjYsP1vOdvaOMhhX0_yIzVlqes-f4YnwO5ASWx8AOOEF6iA","status":"true"}

可以看到,可以得到正常的返回结果。

 

API Gateway生成客户端SDK包

点开“SDK生成”选项页,在平台选“Android”。下面展开的内容,都和我们正在开发的Android App 包名有关,我们前面已经定好包名为 com.aws.cognitowechat。相应的这里几项这样填写:

Group ID 填写com.aws

Invoker package 填写完整包名com.aws.cognitowechat

Artifact ID 填写cognitowechat

Artifact version 填写自己编排的版本号,比如1.0.0。

然后点击Generate SDK按钮,弹出下载文件对话框,保存到本机即可。

Android客户端集成Amazon Cognito验证

我们打开Android Studio,在AndroidManifest.xml中添加访问Internet权限。

 <uses-permission android:name="android.permission.INTERNET"/>

 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

 <uses-permission android:name="android.permission.READ_PHONE_STATE"/>

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

在 build.gradle中的 dependencies 段加上如下引用。

implementation 'com.amazonaws:aws-android-sdk-core:2.9.0'

implementation 'com.amazonaws:aws-android-sdk-apigateway-core:2.9.0'

implementation 'com.amazonaws:aws-android-sdk-cognito:2.9.0'

implementation 'com.amazonaws:aws-android-sdk-cognitoauth:2.9.0'

implementation 'com.amazonaws:aws-android-sdk-cognitoidentityprovider:2.9.0'

implementation 'com.amazonaws:aws-android-sdk-s3:2.9.0'

这些是调用API Gateway和Amazon Cognito所需要的AWS SDK,重新构建一下即可。

前面下载的API Gateway的SDK是一个ZIP压缩包,我们解压只提取其中以下几个文件:

CognitoWechatClient.java

model/AuthenticationRequestModel.java

model/AuthenticationResponseModel.java

把解压出来的3个文件复制粘贴到com.aws.cognitowechat包中。

我们回顾本系列第一篇的讲解,在Android App中访问AWS资源实际是通过Amazon Cognito的开发人员验证的身份,所以核心的代码就是实现一个DeveloperAuthenticationProvider,然后以它的实例作参数初始化调用AWS资源的客户端类,如

DeveloperAuthenticationProvider developerProvider = new DeveloperAuthenticationProvider
        (null, COGNITO_POOL_ID, getApplicationContext(), REGION);
CognitoCredentialsProvider credentialsProvider = new CognitoCredentialsProvider(developerProvider, REGION);
AmazonS3 s3 = new AmazonS3Client(credentialsProvider);

 

我们先实现这个DeveloperAuthenticationProvider类。详细源码请见后附源码库。主要注意以下几点:

// 这里写上和我们在Cognito身份池中设定的开发人员提供商名称。

private static final String developerProvider = “cn.aws.cognitowechat”;

必须实现的refresh()和getIdentityId()方法不能接收参数,而我们要调用后端API接口时还要传递微信登录验证需要的code参数,所以我们做了一个类的属性值,用于传递这个code参数值。

public DeveloperAuthenticationProvider(String accountId, String identityPoolId, Context context, Regions region, String code) {
    super(accountId, identityPoolId, region);
    // 把调用 API Gateway 相关的客户端初始化出来
    AWSCredentialsProvider apiCredentialsProvider = new CognitoCachingCredentialsProvider(context, identityPoolId, region);
    // 使用中国的区域时 ApiClientFactory 不能自动识别出区域来,需要自己再用 region() 方法指定一下
    ApiClientFactory factory = new ApiClientFactory().region(MainActivity.REGION.getName()).credentialsProvider(apiCredentialsProvider);
    Log.d(TAG, "DeveloperAuthenticationProvider: code="+code);
    this.apiClient = factory.build(CognitoWechatClient.class);
    this.code = code;
}

然后在实现的refresh()方法中调用我们已经实现了微信登录逻辑的后端API。

public String refresh() {
    // Override the existing token
    setToken(null);

     AuthenticationRequestModel authRequest = new AuthenticationRequestModel();
    authRequest.setCode(code);
    AuthenticationResponseModel authResponse = apiClient.loginwxPost(authRequest);
    Log.d(TAG, "refresh: userid=" + authResponse.getUserId() + " IdentityId= " + authResponse.getIdentityId() + " OpenIdToken=" + authResponse.getOpenIdToken());
    identityId = authResponse.getIdentityId();
    String token = authResponse.getOpenIdToken();

    update(identityId, token);
    return token;

}

最后回到MainActivity.java,把前述授权访问AWS资源的代码加入到onResume() 方法获得微信登录的code参数后面就完成了整个示例。

DeveloperAuthenticationProvider developerProvider = new DeveloperAuthenticationProvider

                            (null, COGNITO_POOL_ID, getApplicationContext(), REGION, WX_CODE);

                    CognitoCredentialsProvider credentialsProvider = new CognitoCredentialsProvider(developerProvider, REGION);

                    AmazonS3 s3 = new AmazonS3Client(credentialsProvider);

                    // BJS 区需要特别指定一下 region 参数

                    s3.setRegion(Region.getRegion(REGION));

// 我们以列出S3桶名称来演示已获得S3只读权限

                    List<Bucket> bucketList = s3.listBuckets();

                    StringBuilder bucketNameList = new StringBuilder("My S3 buckets are:\n");

                    for (Bucket bucket : bucketList) {

                        bucketNameList.append(bucket.getName()).append("\n");

                    }

                    setHint(txtHint, "Login succeeded.\n" + bucketNameList);

测试执行,可以看到列出了我自己的Amazon S3桶名称。

小结

这一篇中我们最终完成了Android App集成Amazon Cognito开发者身份验证,实现了授权并访问AWS资源。

文档链接:

AWS Toolkit for Eclipse

https://aws.amazon.com/eclipse/

API Gateway 的Android SDK使用详解

https://aws.amazon.com/cn/blogs/china/api-gateway-android-sdk/

Amazon Cognito 经过开发人员验证的身份 (身份池)

https://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/developer-authenticated-identities.html

源码链接

后端API源码

https://github.com/xfsnow/serverless/tree/master/CognitoWechat

Android客户端源码

https://github.com/xfsnow/android/tree/master/CognitoWechat

索引

Amazon Cognito 集成微信登录部署系列(一)Cognito身份池、Dynamodb表和创建Lambda函数
Amazon Cognito 集成微信登录部署系列(二)用Lambda开发服务端API
Amazon Cognito 集成微信登录部署系列(三)与 API Gateway 集成、处理输入参数、返回响应结果
Amazon Cognito 集成微信登录部署系列(四)实现验证逻辑、发布 API
Amazon Cognito 集成微信登录部署系列(五)客户端集成 Cognito 验证

本篇作者

薛峰

亚马逊AWS解决方案架构师,AWS的云计算方案架构的咨询和设计,同时致力于AWS云服务在国内和全球的应用和推广,在大规模并发应用架构、移动应用以及无服务器架构等方面有丰富的实践经验。在加入AWS之前曾长期从事互联网应用开发,先后在新浪、唯品会等公司担任架构师、技术总监等职位。对跨平台多终端的互联网应用架构和方案有深入的研究。