在上一篇中我们实现了对接微信开放平台验证微信用户的业务逻辑,并调试通了Lambda函数和API Gateway。在本篇中,我们将最终完成Android客户端,实现授权并访问AWS资源。
API Gateway部署 API
最后我们把这个 API 发布出来。在API控制台点击操作按钮,选择部署API,首次部署,我们在部署阶段下拉菜单选择[新阶段],阶段名称输入“test”,点击部署按钮即可。然后会跳转到“test 阶段编辑器”。可以看到显示调用 URL类似 https://1234567890.execute-api.cn-north-1.amazonaws.com.cn/test。因为这个方法是 POST方式提交,所以我们可以用curl命令行方式测试一下。
$ curl -d'{"code":"001YYVIG19Qt700dmWHG1nDUIG1YYVI7"}' 'https://1234567890.execute-api.cn-north-1.amazonaws.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 验证
本篇作者