はじめに
概要
前回の記事の続きとなります。
環境
- php: 8.0
- Laravel: 8.*
仕様
前回同様、外部APIのTwilio によるSMSでの二段階認証を用いた会員登録機能に対するFeatureテストを書くということで考えてみます。
処理の流れ
- 会員情報を入力する
- 登録した電話番号にSMSで認証コードを送信する
- 送信した認証コードを検証する(届かなければ再送可)
- 認証が成功すればログイン
この記事では3,4の処理について説明致します。
SMS認証処理
前回まで2の認証コードを送る処理については説明したので、次にそのコードを受け取って認証する処理を実装します
namespace App\Http\Controllers;
use App\Verify\Service;
use Illuminate\Http\Request;
use Illuminate\Support\MessageBag;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use App\Traits\InternationalTelTrait;
use Illuminate\Foundation\Auth\RedirectsUsers;
class VerifySmsController extends Controller
{
use RedirectsUsers;
use InternationalTelTrait;
/**
* リダイレクト先
*
* @var string
*/
protected $redirectTo = '/login';
/**
* SMS認証インスタンス
*
* @var Service
*/
protected $verify;
/**
* SMS認証のインスタンスをサービスコンテナから取得しコンストラクタインジェクション
*
* @return void
*/
public function __construct(Service $verify)
{
$this->verify = $verify;
}
/**
* SMS用の認証コード入力画面表示
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\View\View|\Illuminate\Http\Response
*/
public function show()
{
// 認証済みの場合リダイレクト
return $this->guard()->user()->hasVerifiedTel()
? redirect($this->redirectPath())
: view('verify-sms');
}
/**
* 電話番号を認証する
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function verify(Request $request)
{
$user = $this->guard()->user();
// 認証済みの場合はログイン画面にリダイレクトさせる
if ($user->hasVerifiedTel()) {
return redirect($this->redirectPath());
}
$code = $request->post('code');
$internationalTel = $this->convertToInternationalCallFormat($user->tel);
// 認証コードのチェック
$verification = $this->verify->checkVerification($internationalTel,$code);
if($verification->isValid()) {
$user->changeFlagAsVerified();
return view('registered');
}
$errors = new MessageBag();
foreach ($verification->getErrors() as $error) {
$errors->add('verification',$error);
}
return view('verify-sms')->withErrors($errors);
}
前回同様、コンストラクタで該当のTwilioのサービスクラスをコンストラクタインジェクションしています。
実際にSMSの認証処理を行っているのはverifyメソッド内で$this->verify->checkVerificationでTwilioのサービスクラスのメソッドを呼び出しているところになります。
また今回この処理の中身については触れませんがその前の行で$this->convertToInternationalCallFormatというtraitを作って電話番号を国際電話に対応した形式に変換しています。
これはTwilioが対応している電話番号が国際電話番号形式になるためです。
そしてTwilioのサービスクラスでは送られてきたSMS認証パスコードが合致しているかチェックしています。
上記省略
/**
* Twilio Verify V2 APIによる検証コードの確認
*
* @param $tel
* @param $code
* @return Object sid|MessageBag
*/
public function checkVerification($tel, $code)
{
try {
$verification_check = $this->client->verify->v2->services($this->verification_sid)
->verificationChecks
// 認証コード発行
->create($code, ['to' => $tel]);
// 認証コードの発行に成功ならsidを返却
if($verification_check->status === 'approved') {
return new $verification_check->sid;
}
} catch (TwilioException $exception) {
// エラーメッセージ発行
$messages = new MessageBag();
$messages->add('verification', "認証に失敗しました");
}
}
また合致していてれば下記のようにモデル内でフラグを更新し、認証完了画面に遷移させています。
public function changeFlagAsVerified()
{
return $this->update([
'flag' => $this::SMS_VERIFY
]);
}
SMS認証の流れについては以上となります。
次回ここまで実装してきた機能についてのテストの書き方を解説します!