注册

uniapp 手机号码一键登录保姆级教程

背景


通过uniapp来开发App,目前内部上架的App产品现有的登录方式有「账号/密码」 和 「手机号/验证码」两种登录方式;但这两种方式还是不够便捷,目前「手机号一键登录」是替代短信验证登录的下一代登录验证方式,能消除现有短信验证模式等待时间长、操作繁琐和容易泄露的痛点。


因此,结合市面上的主流App应用,以及业务方的需求,我们的App产品也需要增加「手机号一键登录」功能。 DCloud联合个推公司整合了三大运营商网关认证的服务,通过运营商的底层SDK,实现App端无需短信验证码直接获取手机号。


uni官方提供了对接的方案文档,可自行查阅,也可继续阅读本文


准备工作


1 目前支持的版本及运营商



  • 支持版本:HBuilderX 3.0+
  • 支持项目类型:uni-app的App端,5+ App,Wap2App
  • 支持系统平台: Android,iOS
  • 支持运营商: 中国移动,中国联通,中国电信

2 费用


2.1 运营商费用

目前一键登录收费规则为每次登录成功请求0.02元,登录失败则不计费。


2.2 云空间费用

开通uniCloud是免费的,其中阿里云是全免费,腾讯云是提供一个免费服务空间。


阿里云

选择阿里云作为服务商时,服务空间资源完全免费,每个账号最多允许创建50个服务空间。阿里云目前处于公测阶段,如有正式业务对稳定性有较高要求建议使用腾讯云。


image.png


阿里云的服务空间是纯免费的。但为避免资源滥用,有一些限制,见下:


image.png



除上面的描述外,阿里云没有其他限制。
因为阿里云免费向DCloud提供了硬件资源,所以DCloud也没有向开发者收费。如果阿里云后续明确了收费计划,DCloud也会第一时间公布。



腾讯云

选择腾讯云作为服务商时,可以创建一个免费的服务空间,资源详情参考腾讯云免费额度;如想提升免费空间资源配额,或创建更多服务空间,则需付费购买。


image.png


2.3 云函数费用

如果你的一键登录业务平均每天获取手机号次数为10000次,使用阿里云正式版云服务空间后,对应云函数每天大概消耗0.139元


接入


1 重要前置条件



  • 手机安装有sim卡
  • 手机开启数据流量(与wifi无关,不要求关闭wifi,但数据流量不能禁用。)
  • 开通uniCloud服务(但不要求所有后台代码都使用uniCloud)
  • 开发者需要登录 DCloud开发者中心,申请开通一键登录服务。

2 开发者中心-开通一键登录服务


此官方文档详细步骤开通一键登录服务,开通后将当前项目加入一键登录内,审核2-3天;


3 开通uniCloud


一键登录在客户端获取 access_token 后,必须通过调用uniCloud中云函数换取手机号码,
所以需要开通uniCould;


登录uniCloud中web控制台里,新建服务空间,开通uniCloud


在uniCloud的云函数中拿到手机号后,可以直接使用,也可以再转给传统服务器处理,也可以通过云函数url化方式生成普通的http接口给5+ App使用。


4 客户端-一键登录


当前项目关联云空间

项目名称点击右键,创建云环境,创建的云环境应与之前开通的云空间类型保持一致,我这里选择腾讯云;


image.png


创建好后当前项目下会多个文件夹「uniCloud」,点击右键关联创建好的云空间


image.png


image.png


关联成功


image.png


获取可用的服务提供商(暂时作用不大)

一键登录对应的 provider ID为 'univerify',当获取provider列表时发现包含 'univerify' ,则说明当前环境打包了一键登录的sdk;


uni.getProvider({
service: 'oauth',
success: function (res) {
console.log(res.provider)// ['qq', 'univerify']
}
});

参考文档


预登录(可选)

预登录操作可以判断当前设备环境是否支持一键登录,如果能支持一键登录,此时可以显示一键登录选项;


uni.preLogin({
provider: 'univerify',
success(){ //预登录成功
// 显示一键登录选项
},
fail(res){ // 预登录失败
// 不显示一键登录选项(或置灰)
// 根据错误信息判断失败原因,如有需要可将错误提交给统计服务器
console.log(res.errCode)
console.log(res.errMsg)
}
})

参考文档


请求登录授权

弹出用户授权界面。根据用户操作及授权结果返回对应的回调,拿到 access_token,此时客户端登录认证完成;设置自定义按钮等;后续「需要将此数据提交到服务器获取手机号码」


uni.login({
provider: 'univerify',
univerifyStyle: { // 自定义登录框样式
//参考`univerifyStyle 数据结构`
},
success(res){ // 登录成功 在该回调中请求后端接口,将access_token传给后端
console.log(res.authResult); // {openid:'登录授权唯一标识',access_token:'接口返回的 token'}
},
fail(res){ // 登录失败
console.log(res.errCode)
console.log(res.errMsg)
}
})

参考文档


获取用户是否选中了勾选框

新增判断是否勾选一键登录相关协议函数;


uni.getCheckBoxState({
success(res){
console.log(res.state) // Boolean 用户是否勾选了选框
console.log(res.errMsg)
},
fail(res){
console.log(res.errCode)
console.log(res.errMsg)
}
})

参考文档


用access_token换手机号

客户端获取到 access_token 后,传递给uniCloud云函数,云函数中通过uniCloud.getPhoneNumber方法获取真正的手机号。


换取手机号有三种方式:




  1. 在前端直接写 uniCloud.callFunction ,将 access_token 传给指定的云函数。但需要在「云函数内部」请求服务端接口并将电话号码传到服务器;




  2. 使用普通ajax请求提交 access_token 给uniCloud的云函数(不考虑);




  3. 使用普通ajax请求提交 access_token 给自己的传统服务器,通过自己的传统服务器再转发给 uniCloud 云函数。但uniCloud上的「云函数需要做URL化」;




我们目前使用的是第三种,防止电话号码暴露到前端,通过java小伙伴去请求uniCloud云函数,返回电话号码给后端;


// 云函数验证签名,此示例中以接受GET请求为例作演示
const crypto = require('crypto')
exports.main = async(event) => {

const secret = 'your-secret-string' // 自己的密钥不要直接使用示例值,且注意不要泄露
const hmac = crypto.createHmac('sha256', secret);

let params = event.queryStringParameters
const sign = params.sign
delete params.sign
const signStr = Object.keys(params).sort().map(key => {
return `${key}=${params[key]}`
}).join('&')

hmac.update(signStr);

if(sign!==hmac.digest('hex')){
throw new Error('非法访问')
}

const {
access_token,
openid
} = params
const res = await uniCloud.getPhoneNumber({
provider: 'univerify',
appid: 'xxx', // DCloud appid,不同于callFunction方式调用,使用云函数Url化需要传递DCloud appid参数
apiKey: 'xxx', // 在开发者中心开通服务并获取apiKey
apiSecret: 'xxx', // 在开发者中心开通服务并获取apiSecret
access_token: access_token,
openid: openid
})
// 返回手机号给自己服务器
return res
}

res结果


{
"data": {
"code": 0,
"success": true,
"phoneNumber": "166xxxx6666"
},
"statusCode": 200,
"header": {
"Content-Type": "application/json; charset=utf-8",
"Connection": "keep-alive",
"Content-Length": "53",
"Date": "Fri, 06 Nov 2020 08:57:21 GMT",
"X-CloudBase-Request-Id": "xxxxxxxxxxx",
"ETag": "xxxxxx"
},
"errMsg": "request:ok"
}

参考文档


客户端关闭一键登录授权界面

请求登录认证操作完成后,不管成功或失败都不会关闭一键登录界面,需要主动调用closeAuthView方法关闭。完成业务服务登录逻辑后通知客户端关闭登录界面。


uni.closeAuthView()

参考文档


错误码

一键登录相关的错误码


但其中状态码30006,官方未给出相关的说明,但与相关技术沟通得知,该状态码是运营商返回的,大概率是网络信号不好,或者其它等原因造成的,没办法修复,只能是想办法兼容改错误;


目前我们的兼容处理方案是:程序检测判断如果出现该状态码,则关闭一键登录授权页面,并跳转到原有的「手机号验证码」登录页面


参考文档


5 云函数-一键登录


自HBuilderX 3.4.0起云函数需启用uni-cloud-verify之后才可以调用getPhoneNumber接口,扩展库uni-cloud-verify


需要在云函数的package.json内添加uni-cloud-verify的引用即可为云函数启用此扩展,无需做其他调整,因为HbuilderX内部已经集成了该扩展库,只需引入即可,不用安装,代码如下:


{
"name": "univerify",
"extensions": {
"uni-cloud-verify": {} // 启用一键登录扩展,值为空对象即可
}
}

参考文档


6 运行基座和打包


使用uni一键登录,不需要制作自定义基座,使用HBuilder标准真机运行基座即可。在云函数中配置好apiKey、apiSecret后,只要一键登录成功,就会从你的账户充值中扣费。


在菜单中配置模块权限


image.png


参考文档


需要注意的问题


1. 开通手机号一键登录是否同时需要开通苹果登录?


目前只开通手机号一键登录,未开通苹果登录,在我们项目里是可以的,但是App云打包时是会弹框提示的,但是并不影响项目在App Store中发布;


2. 如果同一个token多次反复获取手机号会重复扣费么?


不会,这种场景应该仅限于联调测试使用,正式上线每次都应该获取最新token,避免过期报错;


3. access_token过期时间



  • token过期时间是10分钟
  • 每次请求获取手机号接口时,都应该从客户端获取最新的token
  • 在取号成功时进行扣费,获取token不计费

4. 预登录有效期


预登录有效期为10分钟,超过10分钟后预登录失效,此时调用login授权登录相当于之前没有调用过预登录,大概需要等待1-2秒才能弹出授权界面。 预登录只能使用一次,调用login弹出授权界面后,如果用户操作取消登录授权,再次使用一键登录时需要重新调用预登录。


作者:Wendy的小帕克
来源:juejin.cn/post/7221422131857506359

0 个评论

要回复文章请先登录注册