在 Meteor 中通过 SMS 登录和注册过程

Signin and signup process via SMS in Meteor

我需要在我的 Meteor 应用程序中进行短信验证。

假设我有一个简单的表单(React 风格,因为我在前端使用 React):

<form onSubmit={ this.submitPhone() }>
  <input type='text' size='10' placeholder='Your phone here' />
  <input type='submit' value='Send me a code'/>
</form>

用户输入他的 phone 号码并提交表格。之后,短信代码将发送到输入的号码。并出现一个新表格:

<form onSubmit={ this.submitCode() }>
  <input type='text' size='5' placeholder='Enter code' />
  <input type='submit' value='Sign In'/>
</form>

如果用户正确输入了他的代码,那么 Meteor 应该知道用户已登录(我认为是使用一些 _id)。如果代码不正确,则会显示一条错误消息。

我找到了 Twilio 服务和这个 package,它看起来正是我所需要的。但是完全不知道怎么用

我几个月前在教程中只尝试过 Meteor 的默认帐户 UI 身份验证方式,但实际上我不知道如何做这些事情,尤其是通过 SMS。我不需要我的应用程序中的角色之类的东西,我什至不需要用户名、密码和电子邮件。我只需要有一个用户群 _idphone。所以我只需要让用户能够登录(第一次登录就是用这种方式注册)。

感谢您的帮助,详细的回答正是我这次所需要的。

首先,您需要安装以下软件包之一:

接下来,您还应该安装 okland:accounts-phone package to help enable login via phone number. Their GitHub 提供简单易懂的设置说明。

密码

我强烈建议使用密码和 phone 号码创建用户帐户,因为它是一个很好的安全功能,并且在 Meteor 帐户包中默认也是必需的。

验证过程

我将给出一个使用服务器端 Meteor 方法 的示例,对于前端,您可以相应地编写 React 处理程序。

此示例将使用 HTTP 包,如果您愿意,可以在您的代码中修改它以包含其他包装器包,如 twilio-meteor。

第一步: 注册您的用户并发送验证短信。

createNewUser 方法:

'createNewUser': function (password, phoneNumber) {
    var min = 10000;
    var max = 99999;
    var random = Math.floor(Math.random() * (max - min + 1)) + min;

    var verified = Meteor.users.find({username: phoneNumber}).fetch();
    if (verified.length > 0) {
        if (verified.length == 1 && verified[0].profile.isMobileVerified == 'NO') {
            Meteor.users.remove({username: phoneNumber});
            var user = {username: phoneNumber, password: password, profile: { randomSms: random, isMobileVerified: 'NO' }};
            Meteor.call("sendSMS", random, phoneNumber);
            Accounts.createUser(user);
            return returnSuccess('Successfully created', phoneNumber);
        } else {
            return returnFaliure('Mobile number already exists', phoneNumber);
        }
    } else {
        var user = {username: phoneNumber, password: password, profile: { randomSms: random, isMobileVerified: 'NO' }};
        Meteor.call("sendSMS", random, phoneNumber);
        Accounts.createUser(user);
        return returnSuccess('Successfully created', phoneNumber);
    }    
},

发送短信方法:

'sendSMS': function (code, mobile) {
    console.log(mobile);
    HTTP.call(
        "POST",
        'https://api.twilio.com/{yyyy-dd-mm}/Accounts/' + 
        '{TWILIO_APPKEY}' + '/SMS/Messages.json', {
            params: {
                From: '+11234567890',
                To: mobile,
                Body: "Greetings! Your OTP is " + code
            },
            auth: '{TWILIO_APPKEY}' + ':' + '{TWILIO_PASSWORD}'
        },
        // Print error or success to console
        function (error) {
            if (error) {
                console.log(error);
            }
            else {
                console.log('SMS sent successfully.');
            }
        }
    );
}

第 2 步: 向用户索要验证码和用户输入的校验码

验证短信方法:

'verifySMS': function (code, userid) {
    console.log(userid);
    var sms = Meteor.users.findOne({username: userid}).profile.randomSms;
    if (sms == code) {
        Meteor.users.update({username: userid}, {
            $set: {"profile.isMobileVerified": "YES", "profile.randomSms": "--"}
        });
        return returnSuccess("Yes");
    } else {
        return returnSuccess("No");
    }
},

第 3 步: 从您的 React 代码处理中,如果代码匹配,则批准用户,否则显示适当的错误消息。


更新以处理 OP 的特定用例: (React 代码示例)

要在每次登录前通过 SMS OTP 代码对用户进行身份验证,您需要在每次用户尝试登录时使用 sendSMS 方法,在存储的 AuthCodes 集合中更新它,每次验证代码,以及相应地处理案件。

反应形式: 您将需要在您的 React JSX 代码容器中呈现类似这样的表单。

<form className="new-task" onSubmit={this.handleSubmit.bind(this)} >
    <input
        type="text"
        ref="phoneNumberInput"
        placeholder="Enter Phone Number"
    />
</form>

为登录用户编写 React 函数:

handleSubmit() {
    event.preventDefault();
    // Find the phone number field via the React ref
    const phoneNumber = ReactDOM.findDOMNode(this.refs.phoneNumberInput).value.trim();
    Meteor.call('sendAuthCode', Meteor.userId(), phoneNumber, function(error, result) {
        // Show a popup to user that code has been sent
    });    
}

然后,与上面类似,创建另一个表单让用户输入发送给他们的代码,并将其发送到服务器进行验证,例如

handleAuthCheck() {
    event.preventDefault();
    // Find the phone number field via the React ref
    const phoneNumber = ReactDOM.findDOMNode(this.refs.phoneNumberInput).value.trim();
    const code = ReactDOM.findDOMNode(this.refs.codeInput).value.trim();
    Meteor.call('verifyAuthCode', Meteor.userId(), phoneNumber, code, function(error, result) {
        // handle result accordingly
        // you need to decide how you are going to login user 
        // you can create a custom module for that if you need to
    });    
}

AuthCodes 集合: 您将需要在文件中定义一个集合并将其导出,以便可以在需要的地方导入它。

export const AuthCodes = new Mongo.Collection('authcodes');

Meteor 服务器方法:

发送短信:

'sendAuthCode': function(userId, phoneNumber) {
    var min = 10000;
    var max = 99999;
    var code = Math.floor(Math.random() * (max - min + 1)) + min;
    Meteor.call("sendSMS", code, phoneNumber);
    AuthCodes.insert({ 
        userId: userId, 
        phoneNumber: phoneNumber, 
        code: code 
    });    
}

验证码:

'verifyAuthCode': function(userId, phoneNumber, code) {
    var authCode = AuthCodes.findOne({ phoneNumber: phoneNumber, code: code })   // You can also add userId check for added verification
    if(typeof authCode !== "undefined" && authCode) {
        // verification passed
        return true;
    } else {
        // verification failed
        return false;
    }
}