做项目的时候经常会遇到需要发短信验证手机号的功能,大部分都是直接在前端集成相应的 SDK 去实现的。但不可避免的是,有时候我们需要在后端提供发短信及短信验证码验证的功能,比如有 web,小程序,native App 都需要复用这个功能。
经过调研,目前国外常见的几个支持后端认证的 provider 有以下几个:
经常简单的调研,我们发现 Facebook Account Kit 必须使用他们的 UI 来发送验证码,不适用于我们项目的场景。Twilio 倒是可以用,不过我们最后还是选了 Firebase,主要是我们本来就用的 Google Cloud Platform, 使用 firebase 就很方便,而且它的免费计划支持每个月 10,000 次电话验证,非常适合我们的需求。
不过坑又来了,仔细看了 firebase 的官方文档,我们发现几乎找不到在后端实现它的方式,文档里写的都是在前端用 SDK 的形式集成的。又经过一番折腾,才终于找到了我们能用来发短信和验证的 Google 服务 identify platform。
发送短信
首先,我们需要发短信,可以调用下面的 Google API:
curl -X POST \
'https://www.googleapis.com/identitytoolkit/v3/relyingparty/sendVerificationCode?key=api_key' \
-H 'content-type: application/json' \
-d '{
"phoneNumber": "phone_number",
"recaptchaToken": "recaptcha_token"
}'
如果访问成功,会得到如下的结果:
{
"sessionInfo": "session_info_token"
}
用 Node 简单实现一个 API:
const FIREBASE_API_KEY = 'AIzaSyBi0MBSiB88xCvbti1T8plNTreX-bzZfAw'
const baseUrl = 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/'
router.post('/otp', async (req: Request, res: Response) => {
const { recaptchaToken, phoneNumber } = req.body
const response = await axios.post(
`${baseUrl}sendVerificationCode?key=${FIREBASE_API_KEY}`,
{
phoneNumber,
recaptchaToken,
},
)
return res.json({
sessionInfo: response.data.sessionInfo,
})
})
后面验证的时候需要用到这个 sessionInfo,我们可以保存在后端的数据库里。
验证 OTP
接下来收到短信后,就可以调用另一个 Google API 是用来验证 OTP(One Time Pin)了:
curl -X POST \
'https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPhoneNumber?key=api_key' \
-H 'content-type: application/json' \
-d '{
"sessionInfo": "sessionInfo",
"code":"otp_code"
}'
成功后得到的 response 如下:
{
"idToken": "idToken",
"refreshToken": "refreshToken",
"expiresIn": "3600",
"localId": "localId",
"isNewUser": false,
"phoneNumber": "phone_number"
}
示例代码如下:
router.post('/verification', async (req: Request, res: Response) => {
const { code, sessionInfo } = req.body
const response = await axios.post(
`${baseUrl}verifyPhoneNumber?key=${FIREBASE_API_KEY}`,
{
sessionInfo,
code,
},
)
return res.json(response.data)
})
刷新 Token
另外一个很常用的功能就是自动刷新 token,也有相应的 Google API 可以使用。
curl -X POST \
'https://securetoken.googleapis.com/v1/token?key=api_key' \
-H 'content-type: application/json' \
-d '{
"grant_type": "refresh_token",
"refresh_token": "refresh_token (验证 OTP 后得到的刷新 token)"
}'
这样前端就可以在 idToken 过期后调用刷新 token 的 API 来获得新的 idToken 而不用重新输入验证码。
示例代码如下:
router.post('/token', async (req: Request, res: Response) => {
const { refreshToken } = req.body
const response = await axios.post(
`https://securetoken.googleapis.com/v1/token?key=${FIREBASE_API_KEY}`,
{
grant_type: 'refresh_token',
refresh_token: refreshToken,
},
)
return res.json(response.data)
})
经过实践,这个方案是可行的,不过有以下的一些坑:
- 发短信需要用 reCAPTCHA token,这需要在前端生成。虽然 reCAPTCHA 在前端可以设成 invisible 模式,但是如果检测到可疑活动 (开发和测试人员在测试的时候不断请求就可能触发),隐形的 reCAPTCHA 有时会触发挑战 (Full challenge),页面上会出现下面的 UI:
- 发出的短信的格式是固定的,不能改。
xxxxxx is your verification code for domain_name.
其中 domain_name 是可以在 firebase 控制台配置的。如果这个格式不能满足需求的话,就只能换其他 provider 了。
今天的文章前后端分离用firebase实现手机号认证功能分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:http://bianchenghao.cn/16274.html