check-verification-code.js 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*
  2. * Copyright (C) 2020 Tencent Cloud.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. 'use strict';
  17. const { verificationCodeCollection, verificationCodeExpires, verificationCodeCheckTimes } = require('./config');
  18. /**
  19. * 校验验证码是否正确
  20. * @async
  21. * @param {object} params - 参数包装对象
  22. * @param {string} params.phoneNumber - 手机号码
  23. * @param {string} params.verificationCode - 用户输入的验证码
  24. * @return {Promise<void>} 验证码核验状态(无异常代表正确)
  25. */
  26. async function checkVerificationCode({ phoneNumber, verificationCode }) {
  27. // 配置校验
  28. if (!verificationCodeCollection) {
  29. throw new Error('请在云函数SMS模块中配置verificationCodeCollection');
  30. }
  31. if (!verificationCodeExpires || isNaN(verificationCodeExpires) || verificationCodeExpires <= 0) {
  32. throw new Error('请在云函数SMS模块中配置有效的verificationCodeExpires');
  33. }
  34. if (!verificationCodeCheckTimes || isNaN(verificationCodeCheckTimes) || verificationCodeCheckTimes <= 0) {
  35. throw new Error('请在云函数SMS模块中配置有效的verificationCodeCheckTimes');
  36. }
  37. // 参数校验
  38. if (!phoneNumber) {
  39. throw new Error('手机号码不能为空');
  40. }
  41. if (!verificationCode) {
  42. throw new Error('验证码不能为空');
  43. }
  44. // 自动为无前缀手机号码添加+86前缀
  45. if (!phoneNumber.startsWith('+')) {
  46. phoneNumber = `+86${phoneNumber}`;
  47. }
  48. const db = uniCloud.database();
  49. const verificationCodes = db.collection(verificationCodeCollection);
  50. // 清理过期验证码记录
  51. const result = await verificationCodes
  52. .where({
  53. createTime: db.command.lt(new Date().getTime() - verificationCodeExpires * 60 * 1000)
  54. })
  55. .remove();
  56. if (result.deleted) {
  57. console.log(`已自动清理掉${result.deleted}条过期记录`);
  58. }
  59. // 验证码查询并核对
  60. const {
  61. data: [record]
  62. } = await verificationCodes
  63. .where({
  64. phoneNumber
  65. })
  66. .orderBy('createTime', 'desc')
  67. .limit(1)
  68. .get();
  69. if (!record) {
  70. throw new Error('验证码不正确');
  71. }
  72. // 每个验证码仅支持核验有限次数(防止字典遍历)
  73. if (record.checkCounter >= verificationCodeCheckTimes) {
  74. throw new Error('验证码不正确');
  75. }
  76. // 增加验证码核验次数
  77. if (record.verificationCode !== verificationCode) {
  78. await verificationCodes.doc(record._id).update({
  79. checkCounter: record.checkCounter + 1
  80. });
  81. throw new Error('验证码不正确');
  82. }
  83. // 验证成功后异步删除验证码记录
  84. try {
  85. verificationCodes
  86. .where({
  87. phoneNumber
  88. })
  89. .remove();
  90. } catch (error) {
  91. console.log(error);
  92. }
  93. }
  94. module.exports = checkVerificationCode;