该篇blog主要记录博主实现app手机号一键登录功能,集成的是阿里云号码认证服务,主要简单记录一下实现的过程,先附上实现最后app一键登录的效果:
在记录一键登录实现逻辑之前,你应该了解一下阿里的认证方案、一键登录和本机号校验:
前提条件
整体实现流程
步骤一:开通号码认证服务
- 访问号码认证服务产品详情页。
- 单击立即开通或访问产品控制台。
- 进入控制台首页,勾选我已阅读并同意《号码认证服务协议》。
- 单击立即开通,完成产品开通。
步骤二:添加认证方案
具体操作,请参见 认证方案管理。
认证方案管理:
认证方案用于标识App下的认证场景,一般一个认证方案对应一个App包名/包签名或者BundleId。系统调用过程中需要使用对应的方案Code。本文为您介绍如何添加认证方案、修改相关配置如认证方式,以及删除认证方案。
-
登录号码认证产品控制台。
-
在左侧导航栏上,选择号码认证服务 > 认证方案管理。
-
根据相应功能填写信息,添加认证方案。
-
一键登录和本机号码校验、活体认证、短信认证:
-
选择iOS或Android页签,再单击+添加认证方案。
-
填写方案名称、App名称等信息。Android操作系统需要填写应用包名及包签名,iOS操作系统需要填写BundleID。
短信认证功能还需在认证方式一栏勾选短信验证码,绑定对应签名。建议使用您的App名称作为签名,提高签名审核通过率。若需要添加新的签名,可单击创建签名。若没有可用的短信签名,可绑定赠送的签名进行测试,待正式签名审核通过后再修改绑定签名,详情请参见修改方案配置。
**
说明 方案名称和App名称建议输入实际上线的App名称。
-
-
代码逻辑实现
pom依赖
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dypnsapi20170525</artifactId>
<version>1.0.2</version>
</dependency>
核心接口
package org.jeecg.modules.base.service;
import com.aliyun.dypnsapi20170525.models.GetMobileResponse;
import com.aliyun.dypnsapi20170525.models.VerifyMobileResponse;
import javax.servlet.http.HttpServletRequest;
/**
* 开放API接口 服务类
*
* @author: jacklin
* @since: 2022/03/28 9:38
**/
public interface IOpenAPIService {
/**
* 调用GetMobile完成一键登录取号
*
* @param accessToken APP端SDK获取的登录token,必填
* @param outId 外部流水号,非必填
* @author: jacklin
* @since: 2021/4/17 9:41
**/
GetMobileResponse getMobile(String accessToken, String outId, HttpServletRequest request);
/**
* 调用verifyMobile完成本机号码校验认证
*
* @param accessCode APP端SDK获取的登录token,必填
* @param phoneNumber 手机号,必填
* @param outId 外部流水号,非必填
* @author: jacklin
* @since: 2021/4/17 11:18
**/
VerifyMobileResponse verifyMobile(String accessCode, String phoneNumber, String outId, HttpServletRequest request);
/**
* 根据键名查询参数配置信息
*
* @param configKey 参数键名
* @return configValue 参数键值
* @author: jacklin
* @since: 2022/1/15 15:43
**/
String selectConfigValueByKey(String configKey, HttpServletRequest request);
}
接口实现类
package org.jeecg.modules.base.service.impl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.aliyun.dypnsapi20170525.models.GetMobileRequest;
import com.aliyun.dypnsapi20170525.models.GetMobileResponse;
import com.aliyun.dypnsapi20170525.models.VerifyMobileRequest;
import com.aliyun.dypnsapi20170525.models.VerifyMobileResponse;
import com.aliyun.teaopenapi.models.Config;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.dto.SystemConfigDTO;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.global.GlobalWebSiteValue;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.base.mapper.BaseCommonMapper;
import org.jeecg.modules.base.service.IOpenAPIService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
/**
* 开放API接口 服务实现类
*
* @author: jacklin
* @since: 2021/03/29 9:39
**/
@Slf4j
@Service
public class OpenAPIServiceImpl implements IOpenAPIService {
@Autowired
private RedisUtil redisUtil;
@Resource
BaseCommonMapper baseCommonMapper;
/**
* 使用AK&SK初始化账号Client
**/
public static com.aliyun.dypnsapi20170525.Client createClient(String accessKeyId, String accessKeySecret) throws Exception {
Config config = new Config()
.setAccessKeyId(accessKeyId)
.setAccessKeySecret(accessKeySecret);
// 访问的域名
config.endpoint = "dypnsapi.aliyuncs.com";
return new com.aliyun.dypnsapi20170525.Client(config);
}
/**
* 响应内容格式:
* {
* "Message": "请求成功",
* "RequestId": 8906582,
* "Code": "OK",
* "GetMobileResultDTO": {
* "Mobile": 121343241
* }
* }
**/
@Override
public GetMobileResponse getMobile(String accessToken, String outId, HttpServletRequest request) {
com.aliyun.dypnsapi20170525.Client client = null;
GetMobileResponse response = new GetMobileResponse();
try {
//从数据库查询获取短信全局配置数据,存在从缓存里取
String accessKeyId = this.selectConfigValueByKey(CommonConstant.SMS_ACCESS_KEY_ID, request);
String accessKeySecret = this.selectConfigValueByKey(CommonConstant.SMS_ACCESS_KEY_SECRET, request);
if (StringUtils.isNoneEmpty(accessKeyId, accessKeySecret)) {
client = createClient(accessKeyId, accessKeySecret);
GetMobileRequest mobileRequest = new GetMobileRequest();
mobileRequest.setAccessToken(accessToken);
mobileRequest.setOutId(outId);
response = client.getMobile(mobileRequest);
} else {
log.error("阿里云号码认证(一键登录)失败,获取系统配置秘钥为空!");
}
} catch (Exception e) {
log.error(response.body.getMessage());
}
return response;
}
/**
* 响应格式:
* {
* "Message": "请求成功",
* "RequestId": 8906582,
* "Code": "OK"
* "GateVerifyResultDTO": {
* "VerifyResult": "PASS",
* "VerifyId": 121343241
* }
* }
**/
@Override
public VerifyMobileResponse verifyMobile(String accessCode, String phoneNumber, String outId, HttpServletRequest request) {
com.aliyun.dypnsapi20170525.Client client = null;
VerifyMobileResponse verifyMobileResponse = new VerifyMobileResponse();
try {
//从数据库查询获取短信全局配置数据,存在从缓存里取
String accessKeyId = this.selectConfigValueByKey(CommonConstant.SMS_ACCESS_KEY_ID, request);
String accessKeySecret = this.selectConfigValueByKey(CommonConstant.SMS_ACCESS_KEY_SECRET, request);
if (StringUtils.isNoneEmpty(accessKeyId, accessKeySecret)) {
client = createClient(accessKeyId, accessKeySecret);
VerifyMobileRequest verifyMobileRequest = new VerifyMobileRequest();
verifyMobileRequest.setAccessCode(accessCode);
verifyMobileRequest.setPhoneNumber(phoneNumber);
verifyMobileRequest.setOutId(outId);
verifyMobileResponse = client.verifyMobile(verifyMobileRequest);
} else {
log.error("本机号码校验认证失败,获取系统配置短信秘钥信息为空");
}
} catch (Exception e) {
log.error(verifyMobileResponse.body.getMessage());
}
return verifyMobileResponse;
}
@Override
public String selectConfigValueByKey(String configKey, HttpServletRequest request) {
Integer tenantId = GlobalWebSiteValue.getTenantId(request);
String cacheConfigKey = "TENANT_ID_" + tenantId + "_" + configKey;
//如果缓存存在走缓存取
String configValue = Convert.toStr(redisUtil.get(cacheConfigKey));
if (StringUtils.isNotBlank(configValue)) {
//log.info("短信秘钥缓存存在,从缓存获取~");
return configValue;
}
SystemConfigDTO systemConfigDTO = baseCommonMapper.selectSystemConfigByConfigKey(configKey);
if (ObjectUtil.isNotNull(systemConfigDTO)) {
//入缓存
redisUtil.set(cacheConfigKey, systemConfigDTO.getConfigValue());
return systemConfigDTO.getConfigValue();
}
return StringUtils.EMPTY;
}
}
只需要在你的登录接口调用IOpenAPIService.getMobile()方法,比如:
GetMobileResponse response = openApiService.getMobile(loginToken, "", request);
到这步实际上就已经实现一键登录的整个过程了。