
NexmoでDjangoアプリに二要素認証を追加する
所要時間:6 分
私は以前、Vonageブログで私の「Kittens & Co」ビジネス用のデモ・アプリケーションを使って、二要素認証への愛を示した。 「Kittens & Co "ビジネス.面白いことに、誰もが同じように猫が好きなわけではなく、犬が好きな人もいれば、他の動物が好きな人もいる。
ちょっとした世論調査をしてみよう
このチュートリアルでは、Django サイトに二要素認証を追加する方法を紹介します。 Vonage Verify API を使います。.この目的のために、私は 「Pollstr"- という小さなアプリを作りました。名前に "e "がないので、一夜にして成功することはわかっている。私は二要素認証を追加して、人々が本当に本人であることを確認し、私のポールのスパムを防止したいと考えています。
Pollstr screenshot
アプリのスタート地点は以下からダウンロードできる。 Githubからダウンロードし、ローカルで実行することができる。
次に次のサイトにアクセスします。 127.0.0.1:8000にアクセスし、投票をしてみてください。以下の認証情報でログインできます:
ユーザー名
testのパスワードが必要だ:
test1234
デフォルトでは、このアプリは Django 組み込みの認証フレームワークを使って登録とログインを実装していますが、このチュートリアルのほとんどは、他の認証方法を使うアプリにも同様に適用できます。さらに、アプリをきれいにするためにいくつかのブートストラップを追加しました。
この出発点のコードはすべて beforeブランチにあります。これから追加するコードはすべて、Githubの ブランチにあります。ブランチにあります。便宜上 をご覧ください。にもあります。
2FAのためのVonage Verify
Verifyは、わずか2回のAPIコールで電話認証を実装する、手間のかからない安全な方法です!ほとんどの二要素認証システムでは、独自のトークン、トークンの有効期限、再試行、SMS送信を管理する必要があります。Vonage Verifyはこのすべてを管理します。
私たちのアプリにVonage Verifyを追加するために、以下の変更を行います:
を追加する
phone_numberを追加します。ビューに
TwoFactorMixinをビューに追加して、ユーザーがログインしていることを確認します。新規ユーザーのために新しい電話番号を記録する
ユーザーに認証コードを送る
Numbersに送られたコードをVerifyする。
電話番号の追加
Django のデフォルトのユーザモデルには電話番号がありません。これを行う方法はいくつかありますが、今回は新しいコードをすべて新しい two_factorアプリに格納します。
これによって /two_factorフォルダに大量の新しいファイルが生成される。を開き /two_factor/models.pyを開き、ユーザーとOne-to-Oneリレーションを持つ新しいモデルを追加しましょう。
# two_factor/models.py
...
from django.contrib.auth.models import User
class TwoFactor(models.Model):
number = models.CharField(max_length=16)
user = models.OneToOneField(User)次に、このモデルのマイグレーションを生成したい。 two_factor.apps.TwoFactorConfigを INSTALLED_APPS.
# pollstr/settings.py
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'two_factor.apps.TwoFactorConfig',
'django.contrib.admin',
...
]これでマイグレーションを生成し、データベースを移行することができます:
TwoFactorMixinの追加
私たちのDjangoアプリは クラスベースのビューを使用しており、カスタムの "mixin" を使ってビューごとに独自の動作を追加できます。現在は LoginRequiredMixinを使って、投票する前にログインしていることを確認しています。
# polls/views.yml
class OptionsView(LoginRequiredMixin, DetailView):
...このチェックにTwoFactorレイヤーを追加するために TwoFactorMixinを実装します。まだ書いていませんが、この新しいミキシンを使うようにビューを変更することから始めましょう。
# polls/views.py
from two_factor.mixins import TwoFactorMixin
class OptionsView(TwoFactorMixin, DetailView):
...
class ResultsView(TwoFactorMixin, DetailView):
...
class VoteView(TwoFactorMixin, View):
...では、このミキシンを two_factorアプリに追加してみましょう:
# two_factor/mixins.py
from django.contrib.auth.mixins import UserPassesTestMixin
from django.core.urlresolvers import reverse
class TwoFactorMixin(UserPassesTestMixin):
def test_func(self):
user = self.request.user
return (user.is_authenticated and "verified" in self.request.session)
def get_login_url(self):
if (self.request.user.is_authenticated()):
return reverse('two_factor:new')
else:
return reverse('login')ここで行っているのは、新しいミキシンを作成することです。 UserPassesTestMixin.このミキシンは自動的に test_func関数を自動的に呼び出します。ここで、ユーザがログインしていることと、セッションが検証されていることをチェックします。後者については、単にキー verifiedがセッションに設定されているかどうかをチェックします。このようにセッションを使用することで、複数のマシンでログインしていても、それぞれのマシンで検証を行うことができます。
この get_login関数は UserPassesTestMixinに、テストが失敗した場合にユーザーをリダイレクトするルートを提供します。この場合、ユーザがまったくログインしていない場合と、ログインしているが認証されていない場合の2つのシナリオがあります。
なぜなら、ユーザーをリダイレクトするルートやビューをまだ実装していないからです。次にこれをやってみましょう。
電話番号の選択
Screen Capture of Number Verification Form
ユーザーの確認が必要な場合は、次の場所にリダイレクトされます。 two_factor:newにリダイレクトされ、コードを送信する電話番号の設定または確認を求められます。
# two_factor/urls.py
from django.conf.urls import url
from . import views
app_name = 'two_factor'
urlpatterns = [
url(r'^$', views.NewView.as_view(), name='new'),
url(r'^create/$', views.CreateView.as_view(), name='create'),
url(r'^verify/$', views.VerifyView.as_view(), name='verify'),
]また、次のステップのURLも追加しました。次に、これらのURLをメインアプリにインポートする必要があります。
# pollstr/urls.py
urlpatterns = [
...
url(r'^polls/', include('polls.urls')),
url(r'^2fa/', include('two_factor.urls')),
]アプリが /2fa/にリダイレクトすると NewViewビューをレンダリングしようとします。このビューは TwoFactorモデルをテンプレートが利用できるようにしますが、ユーザーがまだ TwoFactorオブジェクトをまだ持っていない場合、明らかな例外を捕まえて、代わりに初期化しなければなりません。
# two_factor/views.py
from django.views.generic import DetailView
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import TwoFactor
class NewView(LoginRequiredMixin, DetailView):
template_name = 'two_factor/new.html'
def get_object(self):
try:
return self.request.user.twofactor
except TwoFactor.DoesNotExist:
return TwoFactor.objects.create(user=self.request.user)レコードを返そうとするが user.twofactorレコードを返そうとするが、存在しない場合は代わりに初期化してそれを返す。
ビューは two_factor/new.htmlテンプレートがレンダリングされ、ユーザーが電話番号を入力するか、すでに入力されている電話番号を無効フィールドに表示します。無効化されたフィールドの番号がすでに設定されている場合は、後で無視しますが、コードがどの番号に送信されるかをユーザーに思い出させるのに便利です。
<!-- two_factor/templates/two_factor/new.html -->
{% extends 'polls/base.html' %}
{% block content %}
<form class='form-inline' action="{% url 'two_factor:create' %}" method="post">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.GET.next }}">
<p>
To continue we need to verify your phone number.
</p>
<div class="form-group">
<input type="text" name="number" value="{{ object.number }}"
{% if object.number %}disabled{% endif %} class='form-control'>
</div>
<div class="form-group">
<input type="submit" name="name" value="Verify" class="btn btn-primary">
</div>
</form>
{% endblock %}
Bootstrapのオーバーヘッドを無視して、私たちのフォームはいくつかのフィールドを持つ基本的なフォームです:
その
numberにコードを提出する。を指定します。
nextこれは Django 組み込みの機能なので、うまく使いましょう。
フォームが /2fa/createにフォームが送信されたら、Vonageを使ってユーザーにコードを送信する必要があります。
Vonage Verifyを使用する
ボネージ Verifyの使い方は非常に簡単で、基本的には2つのAPIコールに集約される。最初のものは、ユーザーの電話番号に認証コードを送信します。私たちの場合、これは CreateViewで行われます。
コードを送信するには vonagePythonライブラリが必要です。これはすでに requirements.txtに追加しました。 django-dotenvライブラリと一緒に追加しました。 .envファイルから認証情報をロードできるようにするライブラリも一緒に追加した。アプリの依存関係を別の方法で管理したい場合は、pipで直接インストールできます。
ライブラリーは vonageライブラリは、APIキーとシークレットを使ってインスタンス化するか、いくつかの環境変数を設定してインスタンス化することができる。あなたの Vonage API キーとシークレットを取得できます。 ダッシュボード.
これらの環境変数を設定すると、Vonageクライアントを初期化する必要がなくなり、以下のように直接使用できるようになる。
# two_factor/views.py
from django.views.generic import DetailView, View
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.contrib.auth import logout
import nexmo
from .models import TwoFactor
class CreateView(LoginRequiredMixin, View):
def post(self, request):
number = self.find_or_set_number(request)
response = self.send_verification_request(request, number)
if (response['status'] == '0'):
request.session['verification_id'] = response['request_id']
return HttpResponseRedirect(reverse('two_factor:verify')+"?next="+request.POST['next'])
else:
logout(request)
messages.add_message(request, messages.INFO, 'Could not verify your number. Please contact support.')
return HttpResponseRedirect('/')
def find_or_set_number(self, request):
two_factor = request.user.twofactor
if (not two_factor.number):
two_factor.number = request.POST['number']
two_factor.save()
return two_factor.number
def send_verification_request(self, request, number):
client = nexmo.Client()
return client.start_verification(number=number, brand='Pollstr')このコードではいくつかのことを行っている。まず最初に find_or_set_numberを使用して、ユーザーがすでに電話番号を設定しているかどうかをチェックします。 設定されていない場合のみを保存します。
そして nexmo.Client().start_verificationを使って検証を開始する。ここでは2つのパラメータを渡す。 numberユーザーの名前と、送信するテキストメッセージに表示される brandというユーザーフレンドリーな名前を渡します。
次に statusAPIコールが 0であるかどうかをチェックし、もしそうなら request_idをセッションに保存する。これは、後でユーザが受け取ったコードを確認するために、同じ idが必要だからです。
最後に、ユーザーを VerifyViewにリダイレクトします。これは、検証コードを入力するフォームをレンダリングするシンプルなビューです。
# two_factor/views.py
from django.views.generic import DetailView, View, TemplateView
class VerifyView(LoginRequiredMixin, TemplateView):
template_name = 'two_factor/verify.html'そして対応するテンプレート。見ての通り、我々はまだ next値を渡しているので、最終的に正しいポールにリダイレクトすることができます。
<!-- two_factor/templates/two_factor/verify.html -->
{% extends 'polls/base.html' %}
{% block content %}
<form class="form-inline" action="{% url 'two_factor:confirm' %}" method="post">
{% csrf_token %}
<input type="hidden" name="next" value="{{request.GET.next}}">
<p>
We have sent a code to your number. Please type it in below.
</p>
<div class="form-group">
<input type="text" name="code" class="form-control">
</div>
<div class="form-group">
<input type="submit" name="name" value="Confirm" class="btn btn-primary">
</div>
</form>
{% endblock %} ユーザーコードの検証
Screengrab of 2 Factor Authentication Form
このチュートリアルの最後のステップは、ユーザーが提供するコードを確認することです。最初にこのページのルートを追加しましょう。
# two_factor/urls.py
urlpatterns = [
...
url(r'^confirm/$', views.ConfirmView.as_view(), name='confirm'),
]前のステップで、ユーザーは codeフィールドを持つフォームが表示されました。ユーザーがこれを two_factor:verifyURLに送信すると vonageライブラリを呼び出す必要があります。 request_idを使ってライブラリを呼び出す必要があります。
# two_factor/views.py
class ConfirmView(LoginRequiredMixin, View):
def post(self, request):
response = self.check_verification_request(request)
if (response['status'] == '0'):
request.session['verified'] = True
return HttpResponseRedirect(request.POST['next'])
else:
messages.add_message(request, messages.INFO, 'Could not verify code. Please try again.')
return HttpResponseRedirect(reverse('two_factor:verify')+"?next="+request.POST['next'])
def check_verification_request(self, request):
return nexmo.Client().check_verification(request.session['verification_id'], code=request.POST['code'])私たちは nexmo.Client().check_verification関数を使って、コードが request_id.成功した場合、ステータスコードは 0になり、セッションを検証済みとしてマークします。で開始したページにユーザーをリダイレクトする場合、この関数はユーザーをリダイレクトしません。 TwoFactorMixinはユーザーをリダイレクトせず、ポールを表示するようにします。
Using Vonage for 2 Authentication Factor
次のステップ
にはさらに多くのオプションがあります。 Vonage Verify API にはここで説明した以外にも多くのオプションがあります。にはここで説明した以外にもたくさんのオプションがある。ここで紹介したコードはとてもシンプルで、このユーザー・エクスペリエンスを実装する方法はたくさんある。Vonage Verifyシステムは非常に弾力性があり、必要であれば電話にフォールバックし、あなたが何もしなくてもトークンを失効させ、トークンの再利用を防ぎ、検証時間を記録します。
Vonage Pythonライブラリはどのように使うかについて非常に不可知論的です。あなたが次に何を追加するのか知りたいです。ツイートしてください(私は にツイートしてください。)までご連絡ください。