亚马逊AWS官方博客

Amazon Cognito 集成微信登录部署系列(四)实现验证逻辑、发布 API

在上一篇中我们创建了API,并实现了Lambda函数和API的集成。在这一篇中,我们将具体实现对接微信开放平台验证微信用户的业务逻辑。为了简化说明,我们只选取了登录验证的主线业务流程,其中服务端API的主要步骤包括:

  1. 调用微信开放平台接口,使用code参数换取微信平台的access_token。
  2. 调用微信开放平台接口,使用微信平台的access_token获取微信用户的UnionId。
  3. 根据微信用户的UnionId,在DynamoDB表中查询出本系统中的用户userId。
  4. 以本系统中的用户userId调用Cognito接口获取OpenIdTokenForDeveloperIdentity。
  5. 返回结果给客户端。

实际生产环境的业务流程还要包含用户首次验证本系统时,在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 验证

本篇作者

薛峰

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