在上一篇中我们创建了API,并实现了Lambda函数和API的集成。在这一篇中,我们将具体实现对接微信开放平台验证微信用户的业务逻辑。为了简化说明,我们只选取了登录验证的主线业务流程,其中服务端API的主要步骤包括:
- 调用微信开放平台接口,使用code参数换取微信平台的access_token。
- 调用微信开放平台接口,使用微信平台的access_token获取微信用户的UnionId。
- 根据微信用户的UnionId,在DynamoDB表中查询出本系统中的用户userId。
- 以本系统中的用户userId调用Cognito接口获取OpenIdTokenForDeveloperIdentity。
- 返回结果给客户端。
实际生产环境的业务流程还要包含用户首次验证本系统时,在DynamoDB表中尚未保存和微信平台用户关联关系时,引导用户到本系统的验证,比如输入用户名和密码或手机号和短信验证码,验证通过后再保存到DynamoDB表中,再获取OpenIdTokenForDeveloperIdentity并返回结果。我们这里使用已注册用户的单纯登录验证流程,因此在开发调试过程中首次获得UnionId时先手工在DynamoDB表中插入一条记录,以便模拟用户关联关系已存在于DynamoDB表中的情况。
Lambda函数增加实现微信登录验证逻辑
我们先创建一个cn.amazonaws.lambda.cognitowechat.util包,然后放一个常用的 HttpConnection工具类。然后再创建一个WxClient.java类,用于调用微信平台的接口获取相关微信数据,这个类中需要解析JSON数据,所以在pom.xml中增加以下依赖包。
<!-- https://mvnrepository.com/artifact/org.json/json -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180130</version>
</dependency>
WxClient.java类主要就是 2 个方法,用于获取微信平台的access_token以及微信用户的UnionId。详情请见源码,及微信开放平台说明文档《授权后接口调用(UnionID)》。
我们在CognitoWechat里增加验证的主方法authenticateUser(),并以这个方法来调试调用微信平台接口。
private CognitoUser authenticateUser(String code){
WechatUser user = new WechatUser();
WxClient wxClient = new WxClient();
LinkedHashMap<String, String> ret = wxClient.getWxToken(code);
String accessToken = (String) ret.get("access_token");
String openid = (String) ret.get("openid");
user = wxClient.getWxUser(accessToken, openid);
String unionid = user.getUnionid();
System.out.println(TAG+" unionid= "+unionid);
return null;
}
这时,需要我们再打开Android Studio,调试我们已经完成微信登录关联的App,获取一个当前的微信登录的code参数,比如code=061quGYt0DDI1i1tSoXt0s6yYt0quGYY,用于我们后续服务端函数的开发。
先把handleRequest() 方法改成如下这样:
public CognitoWechatResponse handleRequest(Object input, Context context) {
context.getLogger().log("Input: " + input);
CognitoWechatResponse cwResponse = new CognitoWechatResponse();
@SuppressWarnings("unchecked")
LinkedHashMap<String, String> inputHashMap = (LinkedHashMap<String, String>)input;
String code = (String) inputHashMap.get("code");
WechatUser user = authenticateUser(code);
if(user!=null){
cwResponse.setUserId(user.getUserId());
cwResponse.setStatus("true");
}
return cwResponse;
}
然后就可以用刚才获取的code参数,来运行Lambda函数,用于测试微信开放平台接口调用正常。还是在项目右键菜单找到 Amazon Web Services,再点选 Run Function to AWS Lambda…。在弹出的运行对话框中,JSON输入格换成刚才获取的code参数值,然后执行之。
可以看到窗格中输出一系列调试信息,已经从微信开放平台获取了的微信用户信息。
Lambda函数查询DynamoDB表
根据前述模拟已存在的用户情况,我们把刚才获取到的UnionId以及模拟的用户ID如123手工插入到DynamoDB表WechatUser中。然后继续在Lambda函数中增加查WechatUser表的逻辑。我们使用经典的DynamoDBMapper来做一次读表查询即可。
我们在Java工程中添加相应的DynamoDB数据表对象。
package cn.amazonaws.lambda.cognitowechat;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
@DynamoDBTable(tableName = "WechatUser")
public class WechatUser {
private String unionid;
private Integer userId;
@DynamoDBHashKey(attributeName = "unionid")
public String getUnionid() {
return unionid;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
@DynamoDBAttribute(attributeName = "userid")
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public WechatUser() {
}
}
在 authenticateUser()方法里添加以下代码段。
AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.standard()
.withRegion(REGION)
.build();
DynamoDBMapper mapper = new DynamoDBMapper(ddb);
user = mapper.load(WechatUser.class, unionid);
if(user!=null){
Integer userId = user.getUserId();
System.out.println(TAG+" userid= "+userId);
return user;
}
测试一下,在AWS上执行Lambda函数,可以得到从WechatUser表读取出的userid=123。
Lambda函数获取Cognito的OpenIdToken
在CognitoWechat类中增加2个常量,配置上Cognito身份池的参数,这2个参数可以到Amazon Cognito控制台我们前面创建的身份池CognitoWechat中查找。
private static final String IDENTITY_POOL_ID = "cn-north-1:12345678-90ab-cdef-1234-567890abcdef ";
private static final String developerProvider = "cn.aws.cognitowechat";
添加一个新方法getCognitoUser ,用于获取Cognito的OpenIdToken。
private CognitoUser getCognitoUser(Integer userId){
AmazonCognitoIdentity client = AmazonCognitoIdentityClientBuilder.defaultClient();
GetOpenIdTokenForDeveloperIdentityRequest tokenRequest = new GetOpenIdTokenForDeveloperIdentityRequest();
tokenRequest.setIdentityPoolId(IDENTITY_POOL_ID);
HashMap<String, String> map = new HashMap<String, String>();
map.put(developerProvider, userId.toString());
tokenRequest.setLogins(map);
tokenRequest.setTokenDuration(new Long(10001));
GetOpenIdTokenForDeveloperIdentityResult result = client.getOpenIdTokenForDeveloperIdentity(tokenRequest);
CognitoUser cognitoUser = new CognitoUser();
cognitoUser.setUserId(userId);
cognitoUser.setOpenIdToken(result.getToken());
cognitoUser.setIdentityId(result.getIdentityId());
System.out.println(TAG+" identityId = "+result.getIdentityId()+"; getToken = "+result.getToken());
return cognitoUser;
}
再测试一下,在AWS上执行Lambda函数,可以得到从Cognito获取到的identityId和token就可以了。
然后我们把handleRequest()方法写完整,把getCognitoUser()方法返回的结果输出成Lambda函数的响应结果。最后到API Gateway控制台,在API中测试,可以检验整个服务端接口已经调试成功。
小结
这一篇中我们实现了对接微信开放平台验证微信用户的业务逻辑,并调试通了Lambda函数和API Gateway。在下一篇中,我们将最终完成Android客户端,实现授权并访问AWS资源。
索引
Amazon Cognito 集成微信登录部署系列(一)Cognito身份池、Dynamodb表和创建Lambda函数
Amazon Cognito 集成微信登录部署系列(二)用Lambda开发服务端API
Amazon Cognito 集成微信登录部署系列(三)与 API Gateway 集成、处理输入参数、返回响应结果
Amazon Cognito 集成微信登录部署系列(四)实现验证逻辑、发布 API
Amazon Cognito 集成微信登录部署系列(五)客户端集成 Cognito 验证
本篇作者