twilio无法验证手机
There are various approaches used to confirm people are in fact who they say they: reference some aspect of the user herself (e.g. biometrics), ask for something the user knows (e.g. a password), or ask for something the user physically has (e.g. an RFID card). Traditional websites implement single-factor authentication, requiring just a user’s password. But multi-factor authentication on the other hand requires verification from at least two of the different approaches and is considerably more secure.
有多种方法可以用来确认人们实际上是在说他们是谁:参考用户本人的某些方面(例如生物特征识别),询问用户知道的内容(例如密码)或询问用户实际拥有的内容(例如RFID卡)。 传统网站执行单因素身份验证,仅需要用户密码。 但是另一方面,多因素身份验证需要至少两种不同方法的验证,并且安全性要高得多。
Using biometrics to authenticate someone to your website is probably still a long ways off with many technological hurdles and civil liberties concerns to overcome. A more practical approach to multi-factor authentication is to implement options from the other two categories, such as requiring a password and a confirmation token sent to the user via phone either by SMS or voice call (the user knows the password, and has a phone). This is what you’ll learn how to implement in this article.
使用生物识别技术对网站上的某人进行身份验证可能还有很长的路要走,要克服许多技术障碍和公民自由问题。 一种更实用的多因素身份验证方法是从其他两个类别中实现选项,例如要求输入密码和通过SMS或语音呼叫通过电话发送给用户的确认令牌(用户知道密码,并且具有电话)。 这就是您将在本文中学习的实现方法。
Telephony integration can be frustrating if you’re doing it from the ground up, and most of the time it’s not practical to build up your own infrastructure (though possible with commodity hardware and programs like Asterisk). Luckily, Twilio offers the infrastructure and an API which developers can use to write interactive telephony applications without much hassle. I’ll be making use of their services in this article.
如果您是从头开始的话,电话集成可能会令人沮丧,并且在大多数情况下,构建自己的基础结构是不切实际的(尽管可以使用商品硬件和程序,例如Asterisk )。 幸运的是, Twilio提供了基础结构和API,开发人员可以使用它们轻松编写交互式电话应用程序。 我将在本文中利用他们的服务。
You can make and receive phone calls and send and receive text messages with Twilio using TwiML (Twilio Markup Language) and their REST API. You can work directly with the API, or use one of the available helper libraries. The library I’ll use here is twilio-php, the library released and officially supported by Twilio.
您可以使用TwiML(Twilio标记语言)及其REST API使用Twilio拨打和接听电话以及收发短信。 您可以直接使用API,也可以使用可用的帮助程序库之一 。 我将在这里使用的库是twilio-php ,它是Twilio发布并正式支持的库。
So, are you ready to learn how you can implement multi-factor authentication? Read on!
那么,您准备好学习如何实现多因素身份验证了吗? 继续阅读!
Connecting to the Twilio service is as easy as including the twilio-php library and creating a new instance of the Services_Twilio class. The object’s constructor accepts your account’s SID and auth token which are listed on your Twilio account’s dashboard page after you sign up for their service.
连接到Twilio服务就像包含twilio-php库并创建Services_Twilio类的新实例一样容易。 对象的构造函数接受您的帐户的SID和auth令牌,这些令牌在您注册Twilio帐户的仪表板页面后列出。
With an available Services_Twilio instance at your disposal, you can access their API though the account property. account exposes an instance of Services_Twilio_Rest_Account which represents your Twilio account. I’m only using one account here, but it is possible to have multiple sub-accounts. This can be useful for segmenting your interactions depending on your needs. You can learn more about sub-accounts by reading the Twilio documentation.
使用可用的Services_Twilio实例,您可以通过account属性访问其API。 帐户公开一个Services_Twilio_Rest_Account实例,该实例代表您的Twilio帐户。 我在这里只使用一个帐户,但是可以有多个子帐户。 这对于根据您的需求细分互动很有用。 您可以通过阅读Twilio文档来了解有关子帐户的更多信息。
<?php require "Services/Twilio.php"; define("TWILIO_SID", "…"); define("TWILIO_AUTH_TOKEN", "…"); $twilio = new Services_Twilio(TWILIO_SID, TWILIO_AUTH_TOKEN); $acct = $twilio->account;The account instance exposes several other properties, among which are calls and sms_messages. These are instances of objects like Services_Twilio_Rest_Calls and Services_Twilio_Rest_SmsMessages which encapsulate the REST resources used to issue your calls and messages respectively. Yet, you rarely work with these objects beyond their create() methods, and the documentation refers to the properties that expose them as “instance resources.” I’ll do the same to help avoid any confusion.
该帐户实例还具有其他一些属性,其中包括调用和sms_messages。 这些是Services_Twilio_Rest_Calls和Services_Twilio_Rest_SmsMessages类的对象的实例,它们封装了分别用于发出呼叫和消息的REST资源。 但是,除了这些对象的create()方法之外,您很少使用它们,并且文档将这些对象公开为“实例资源”。 我会做同样的事情以帮助避免任何混乱。
Sending an SMS message is done through the create() method of an SMS message instance resource ($acct->sms_messages). The method takes three arguments: the Twilio number of your account (akin to the “from address” of an email), the recipient’s number (the “to address”), and the text of your message (which can be up to 160 characters).
发送SMS消息是通过SMS消息实例资源( $acct->sms_messages )的create()方法完成的。 该方法采用三个参数:您帐户的Twilio号(类似于电子邮件的“发件人地址”),收件人的号码(“收件人地址”)以及邮件的文本(最多160个字符) )。
<?php $code = "1234"; // some random auth code $msg = $acct->sms_messages->create( "+19585550199", // "from" number "+19588675309", // "to" number "Your access code is " . $code );Behinds the scenes, the twilio-php library issues a POST request of some TwiML on your behalf to the Twilio API. An instance of Services_Twilio_Rest_SmsMessage is returned by the call, which encapsulates information about the message. You can see a full list of what information is made available in the documentation, but probably the more important values are exposed by the status and price properties. status reveals the status of the SMS message (either queued, sending, sent, or failed), and price reveals the amount billed to your account for the message.
在后台,twilio-php库代表您向Twilio API发出了一些TwiML的POST请求。 调用返回Services_Twilio_Rest_SmsMessage的实例,该实例封装了有关消息的信息。 您可以在文档中看到提供哪些信息的完整列表,但是status和price属性可能会公开更重要的值。 status显示SMS消息的状态(已排队,正在发送,已发送或失败),而price显示了为该消息记帐到您的帐户的金额。
Initiating a voice call is done through the create() method of a Calls instance resource ($acct->calls). Like sending SMS messages, you need to provide your account number, the recipient’s number, and the message. In this case, however, the message is a URL to a TwiML document that describes the nature of the call.
语音呼叫是通过Calls实例资源( $acct->calls )的create()方法完成的。 与发送SMS消息一样,您需要提供您的帐号,收件人的号码和消息。 但是,在这种情况下,该消息是描述呼叫性质的TwiML文档的URL。
<?php // Note spaces between each letter in auth code. This forces // the speech synthesizer to enunciate each digit. $code = "1 2 3 4"; $msg = $acct->calls->create( "+19585550199", // "from" number "+19588675309", // "to" number "http://example.com/voiceCall.php?code=" . urlencode($code) );Again the library issues a POST request on your behalf and a voice call is made. When the callee answers her telephone, Twilio’s processes retrieve and execute the commands provided in the callback URL’s XML. In the above sample that initiates a voice call, I’ve passed the confirmation code as a GET parameter in the URL to the callback script. When the URL is retrieved by Twilio, PHP will use the parameter when rendering the response.
图书馆再次代表您发出POST请求,并进行语音通话。 当被叫方接听电话时,Twilio的过程将检索并执行回调URL的XML中提供的命令。 在上述发起语音呼叫的示例中,我已将确认代码作为URL中的GET参数传递给了回调脚本。 当Twilio检索到URL时,PHP将在呈现响应时使用该参数。
There are only a handful of TwiML tags you need to construct the call flow, but you can use them to define flows that are quite complex (such as phone tree menus, etc.). A basic call flow for this type of scenario though could be generated by PHP and look something like this:
构造呼叫流只需要几个TwiML标签,但是您可以使用它们来定义非常复杂的流(例如电话树菜单等)。 这种类型的场景的基本调用流程可以由PHP生成,如下所示:
<?php header("Content-Type: text/xml"); $code = isset($_GET["code"]) ? htmlspecialchars($_GET["code"]) : null; $digit = isset($_POST["Digits"]) ? (int)$_POST["Digits"] : null; $url = htmlspecialchars($_SERVER["PHP_SELF"]) . "?code=" . $code; echo '<?xml version="1.0" encoding="UTF-8"?>'; ?> <Response> <?php if (is_null($code)) { ?> <Say>Sorry. An error occurred.</Say> <?php } else { ?> <Gather action="<?php echo $url; ?>" numDigits="1"> <?php if (is_null($digit) || $digit == 1) { ?> <Say>Your access code is <?php echo $code; ?></Say> <?php } ?> <Say>Press 1 to repeat the code.</Say> </Gather> <?php } ?> <Say>Good bye.</Say> </Response>The TwiML tags used here are Response (the root element), Say (provides text that will be spoken by Twilio), and Gather (collects input from the user).
这里使用的TwiML标签是Response (根元素), Say (提供Twilio将Say文本)和Gather (收集来自用户的输入)。
While speaking the text as indicated by the child Say elements, Twilio will also be listening for user input because of Gather, pausing five seconds afterwards to provide a window for the user to enter her response. If Gather times out without input, it exits and executes the subsequent Say text and terminates the call. Otherwise, the input is POSTed back to the action URL for further handling.
在说出儿童“ Say元素所指示的文本时,Twilio还将由于Gather而正在侦听用户输入,此后暂停五秒钟,以为用户提供输入其响应的窗口。 如果“ Gather超时而没有输入,它将退出并执行随后的“ Say文本并终止呼叫。 否则,输入将回传到操作URL,以进行进一步处理。
The Twilio docs for Gather are very good at explaining the behavior and the element attributes you can use to modify the behavior, and even lists a couple samples. I recommend you give it a quick read.
Gather的Twilio文档非常擅长说明行为和可用于修改行为的元素属性,甚至列出了一些示例。 我建议您快速阅读。
There’s one last thing of note before moving on; I’ve added spaces between each digit in the auth code in the initiating script. This forces the speech synthesizer to enunciate each digit saying “one two three four” instead of “one thousand two hundred thirty four.” With speech synthesis, sometimes what we see in text isn’t always what we get. It’s okay to fudge or misspell voice dialog if it results in better clarity and understanding for your callees.
在继续之前还有最后一件事需要注意; 我在启动脚本的auth代码中的每个数字之间添加了空格。 这迫使语音合成器将每个数字说成“一二三四”而不是“一千二百三十四”。 通过语音合成,有时我们在文本中看到的并不总是我们得到的。 可以轻描淡写或拼写错误的语音对话,如果它可以使被呼叫者更加清晰和理解。
Now that you understand the basic workflow for SMS and voice interactions with Twilio, it’s time to see where it fits into the login process. What you’ll see here is pretty straight forward, and I’ve reduced the incidental code for the sake of clarity since the particulars of your own login process will inevitably vary.
现在,您已经了解了与Twilio进行SMS和语音交互的基本工作流程,是时候查看它在登录过程中的适用位置了。 您在这里看到的内容非常简单,为了清楚起见,我减少了附带代码,因为您自己的登录过程的细节不可避免地会有所不同。
The user should be presented with a login form which initiates the process. The form submission leads you to verifying her credentials and rejecting them if they’re bad, but valid credentials shouldn’t immediately authenticate the user to your application. Instead, consider the user “partially authenticated”, a state which allows her to view a second form requesting the code which has been sent to her phone. Only after she submits the correct code should the user be authorized.
应该向用户显示一个启动过程的登录表单。 表单提交使您可以验证她的凭据,如果凭据不好,则将其拒绝,但是有效的凭据不应立即使用户通过您的应用程序进行身份验证。 取而代之的是,将用户视为“部分身份验证”,该状态允许她查看第二个表单,以请求已发送到手机的代码。 只有在她提交了正确的密码之后,才可以授权用户。
<?php session_start(); require "Services/Twilio.php"; define("TWILIO_SID", "…"); define("TWILIO_AUTH_TOKEN", "…"); define("TWILIO_FROM_NUMBER", "+19585550199"); define("TWILIO_VOICE_URL", "http://example.com/voiceCall.php"); define("DB_HOST", "localhost"); define("DB_DBNAME", "test"); define("DB_USER", "dbuser"); define("DB_PASSWORD", "dbpassword"); define("CRYPT_SALT", '$2a$07$R.gJb2U2N.FmZ4hPp1y2CN'); define("AUTH_CODE_LENGTH", 4); $db = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_DBNAME, DB_USER, DB_PASSWORD); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); if ($_SERVER["REQUEST_METHOD"] == "POST") { // first stage of authentication if (empty($_SESSION["username"])) { $username = isset($_POST["username"]) ? $_POST["username"] : ""; $password = isset($_POST["password"]) ? crypt($_POST["password"], CRYPT_SALT) : ""; $query = sprintf("SELECT username, phone_number, code_pref FROM users WHERE username = %s AND password = %s", $db->quote($username), $db->quote($password)); $result = $db->query($query); $row = $result->fetch(PDO::FETCH_ASSOC); $result->closeCursor(); // invalid username/password provided if (!$row) { session_unset(); } // valid username/password else { $_SESSION["isAuthenticated"] = false; $_SESSION["username"] = $row["username"]; // generate and send auth code $code = ""; for ($i = 0; $i < AUTH_CODE_LENGTH; $i++) { $code .= rand(0, 9); } $twilio = new Services_Twilio(TWILIO_SID, TWILIO_AUTH_TOKEN); $acct = $twilio->account; // send code via voice or SMS depending on // the user's preference if ($row["code_pref"] == "voice") { // add spaces to force enunciation $tmpCode = join(" ", string_split($code)); $msg = $acct->calls->create( TWILIO_FROM_NUMBER, $_row["phone_number"], TWILIO_VOICE_URL . "?code=" . urlencode($tmpCode) ); } else { $msg = $acct->sms_messages->create( TWILIO_FROM_NUMBER, $_row["phone_number"], "Your access code is " . $code ); } // "remember" code in session $_SESSION["code"] = $code; } } // second stage authentication else { $code = isset($_POST["code"]) ? $_POST["code"] : ""; if ($code == $_SESSION["code"]) { $_SESSION["isAuthenticated"] = true; unset($_SESSION["code"]); } } } if (!empty($_SESSION["isAuthenticated"])) { ?> <h1>W00t! You're Authenticated!</h1> <?php } // present login forms else { if (empty($_SESSION["username"])) { ?> <h1>Login Step 1</h1> <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post"> <input type="text" name="username"> <input type="password" name="password"> <input type="submit" value="Login"> </form> <?php } else { ?> <h1>Login Step 2</h1> <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post"> <input type="text" name="code"> <input type="submit" value="Confirm"> </form> <?php } }The above code is only meant to be illustrative. In your real-world application, you might want to consider adding the following:
以上代码仅是说明性的。 在实际应用程序中,您可能需要考虑添加以下内容:
Add a link to resend the confirmation code to the user’s phone. 添加链接以将确认代码重新发送到用户的电话。Add a cancel link on the code request form in case the user decides not to continue with the process. With respect to the code above, such a link would need to unset $_SESSION["username"] since the value, besides storing the username, also acts as a “partial authentication” flag with respect to $_SESSION["isAuthenticated"].
如果用户决定不继续该过程,请在代码请求表单上添加一个取消链接。 关于上面的代码,这样的链接将需要取消设置$_SESSION["username"]因为该值除了存储用户名之外,还充当针对$_SESSION["isAuthenticated"]的“部分身份验证”标志。
Add throttling or account locking if an incorrect code has been provided. 如果提供了错误的代码,请添加限制或帐户锁定。 Depending on your level of paranoia or the compliance requirements you face, log the authentication events somewhere. (An application which requires multi-factor authentication is usually sensitive enough to warrant an audit trail!) 根据您的偏执程度或您面临的合规性要求,在某处记录身份验证事件。 (需要多因素身份验证的应用程序通常足够敏感,可以保证进行审核!)Additionally, you may want to put some thought into creating sufficiently complex authentication codes for your purposes. 4-digit numeric codes are pretty common, but you’re not limited to that. If you choose to use letters or a mix of alphanumeric values, I’d suggest avoiding values that can be easily confused (such as the number 0 vs the letter O, the number 1 vs the letter I, etc.).
此外,您可能需要考虑为自己的目的创建足够复杂的身份验证代码。 4位数字代码很常见,但您不仅限于此。 如果您选择使用字母或字母数字值的混合,建议不要使用容易混淆的值(例如,数字0与字母O,数字1与字母I,等等)。
The proliferation of affordable mobile devices and IP-Telephony has added additional channels for interacting with users, and in this article you learn one way to leverage these channels by implementing multi-factor authentication using the “cloud communications” service Twilio.
负担得起的移动设备和IP电话的激增增加了与用户交互的其他渠道,在本文中,您将学习一种通过使用“云通信”服务Twilio实施多因素身份验证来利用这些渠道的方法。
I hope you’ve found this article helpful in understanding both multi-factor authentication and Twilio. Feel free to leave a comment below sharing how you’ve used Twilio or implemented multi-factor authentication in your own applications. I’d love to hear about it!
我希望您发现本文对理解多因素身份验证和Twilio有所帮助。 在下面分享您在自己的应用程序中如何使用Twilio或实现多因素身份验证的方式,在此发表评论。 我很想听听它!
Image via Fotolia
图片来自Fotolia
翻译自: https://www.sitepoint.com/multi-factor-authentication-with-php-and-twilio/
twilio无法验证手机