一部のサイトでは、クイックログインリンクを使用してSMSメッセージを送信できることがあります。これは基本的に同じことです。 このメモに記載されているアプローチの主な違いは、SMSメッセージを送信する代わりに、認証データを入力せずにサイトにアクセスできるリンクを含むQRコードを生成することです。

ちなみに、以下に示すアプリケーションの記述プロセス全体は、スクリーンキャストで見ることができます( YouTubeで利用可能、または1080pのMPEG2ファイルとしてより高品質で利用可能)。
この承認オプションを実装する前に、SMSメッセージを送信するオプションとの違いを見てみましょう。
- SMSメッセージの方が少し安全です:一方では、第三者(特に、SMSゲート、モバイルオペレーター)を介してリンクを送信しますが、他方では、まず、JSを介してリンクを利用できません(したがって、サイトにXSSがある場合、攻撃者はSMSメッセージからリンクを取得することはできません-ただし、QRコードから取得することはできます)、次に、サイトでユーザーが承認されているブラウザを使用してコンピューターに物理的にアクセスしますコンピュータにアクセスするよりも簡単であると同時に、身体にも ユーザーの背景
- 同時に、SMSメッセージはそれほど普遍的ではありません:何らかの理由でセルラー接続がない場合、またはユーザーが使用するモバイルデバイスがセルラーネットワークで動作する可能性を暗示していない場合は動作しません(ただし、カメラがあり、インターネット接続、およびQRコードをスキャンするためのアプリケーションがインストールされているか、簡単にインストールされます)
- SMSメッセージの送信には費用がかかります; QRコードの生成は完全に無料です
- 状況によっては、SMSメッセージは速度と信頼性の指標を大幅に落とす可能性があります(つまり、メッセージが大幅に遅れて到着する場合やまったく届かない場合もあります)。カメラは大丈夫です)
- サイトでは、SMSメッセージを送信するためにユーザーの電話番号が必要ですが、すべてのユーザーがインターネット上のどこかに電話番号を入力するという考えを好むわけではありません
QRコードを使用したオプションは非常に優れていることがわかりました。 そして、高いセキュリティが私たちにとって重要であっても、理論的には誰もQRコードを電子メールで送信したり、毎回パスワードを求めたりすることはありません(便利な大型コンピューターのキーボードでもう一度パスワードを入力すると、ウェブサイトのアドレスを入力するよりもはるかに簡単です+ユーザー名/メールアドレス+モバイルデバイスの仮想キーボードのパスワード)。 それにもかかわらず、QRコードを使用して迅速に入力するための最も簡単で最も基本的なオプションを実装することを提案します。
以下のテキストは、スクリーンキャストと同様に、さまざまな実装機能について説明しています。 アプリケーションをサイトにすばやく追加する場合は、pipを使用してインストールできます。
pip install django-qrauth
この場合、メインのurls.pyにアプリケーションのURLスキームを含めるだけでなく、テンプレートを追加するだけです。 Githubでインストール手順とソースコードを見つけることができます。
以下に、アプリケーションを自分で構築する方法を説明します-たとえば、すぐに何かを編集したい場合など。
そのため、まず、このような承認を追加するDjangoプロジェクトの作業ディレクトリに移動し、新しいアプリケーションを作成します。 たとえば、qrauthのように呼び出します。
python manage.py startapp qrauth
表示されるディレクトリで、qr.pyファイルを作成します。
try: from PIL import Image, ImageDraw except ImportError: import Image, ImageDraw import qrcode.image.base import qrcode.image.pil class PilImage(qrcode.image.pil.PilImage): def __init__(self, border, width, box_size): if Image is None and ImageDraw is None: raise NotImplementedError("PIL not available") qrcode.image.base.BaseImage.__init__(self, border, width, box_size) self.kind = "PNG" pixelsize = (self.width + self.border * 2) * self.box_size self._img = Image.new("RGBA", (pixelsize, pixelsize)) self._idr = ImageDraw.Draw(self._img) def make_qr_code(string): return qrcode.make(string, box_size=10, border=1, image_factory=PilImage)
python-qrcodeモジュールはここで使用されます 。 pipを使用してインストールできます。
pip install qrcode
(白ではなく)背景が透明な画像を取得するために、クラスを特別に使用して画像を作成し、qrcode.image.pil.PilImageから継承します。 背景が白い画像に満足したら、次のように書くだけで十分です。
import qrcode def make_qr_code(string): return qrcode.make(string, box_size=10, border=1)
この場合、qrcode.make(および、それに応じてmake_qr_code関数)によって返される画像のサイズが最適ではないことに注意してください。 たとえば、 optipngを使用すると 、サイズを約70%削減できます(もちろん、品質を損なうことなく)。 ただし、ほとんどの場合、これは原則ではありません。いずれにしても、サイズは小さくなります(数キロバイト以内)。
次に、utils.pyファイルを作成し、ビューで使用する関数を追加します。
import os import string import hashlib from django.conf import settings def generate_random_string(length, stringset="".join( [string.ascii_letters+string.digits] )): """ Returns a string with `length` characters chosen from `stringset` >>> len(generate_random_string(20) == 20 """ return "".join([stringset[i%len(stringset)] \ for i in [ord(x) for x in os.urandom(length)]]) def salted_hash(string): return hashlib.sha1(":)".join([ string, settings.SECRET_KEY, ])).hexdigest()
generate_random_string関数は、指定された長さのランダムな文字列を生成します。 デフォルトでは、文字列はラテンアルファベットの文字(大文字と小文字の両方)と数字で構成されます。
salted_hash関数は、文字列をソルトおよびハッシュします。
views.pyを開いて、ビューを記述します。
import redis from django.contrib.auth.decorators import login_required from django.contrib.auth import login, get_backends from django.contrib.sites.models import get_current_site from django.template import RequestContext from django.shortcuts import render_to_response from django.http import HttpResponse, HttpResponseRedirect, Http404 from django.core.urlresolvers import reverse from django.contrib.auth.models import User from privatemessages.context_processors import \ number_of_new_messages_processor from utils import generate_random_string, salted_hash from qr import make_qr_code @login_required def qr_code_page(request): r = redis.StrictRedis() auth_code = generate_random_string(50) auth_code_hash = salted_hash(auth_code) r.setex(auth_code_hash, 300, request.user.id) return render_to_response("qrauth/page.html", {"auth_code": auth_code}, context_instance=RequestContext(request)) @login_required def qr_code_picture(request, auth_code): r = redis.StrictRedis() auth_code_hash = salted_hash(auth_code) user_id = r.get(auth_code_hash) if (user_id == None) or (int(user_id) != request.user.id): raise Http404("No such auth code") current_site = get_current_site(request) scheme = request.is_secure() and "https" or "http" login_link = "".join([ scheme, "://", current_site.domain, reverse("qr_code_login", args=(auth_code_hash,)), ]) img = make_qr_code(login_link) response = HttpResponse(mimetype="image/png") img.save(response, "PNG") return response def login_view(request, auth_code_hash): r = redis.StrictRedis() user_id = r.get(auth_code_hash) if user_id == None: return HttpResponseRedirect(reverse("invalid_auth_code")) r.delete(auth_code_hash) try: user = User.objects.get(id=user_id) except User.DoesNotExist: return HttpResponseRedirect(reverse("invalid_auth_code")) # In lieu of a call to authenticate() backend = get_backends()[0] user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__) login(request, user) return HttpResponseRedirect(reverse("dating.views.index"))
QRコード(qr_code_page)でページにアクセスすると、50文字のランダムな文字列が生成されます。 次に、 Redis (
pip install redis
を使用してクライアントをインストールできます)で、新しいキーと値のペアが追加され、生成されたランダムな文字列の
pip install redis
ハッシュがキーとして設定され、ユーザーIDが値として設定されます(これは、QRコードの画像、ページに追加され、このユーザーのみが使用できました)。 このキーは有効期限を設定します。例では300秒(5分)が示されています。
テンプレートのコンテキストでは、生成されたランダムな文字列が設定されます。この行は、QRコードを含む画像が返されるアドレスで使用されます(ただし、認証では、ハッシュが使用され、ハッシュを含むアドレスがQRコードに含まれます:このように、他の誰かが画像のアドレスを知っている場合、認可は十分ではありません-認可のためには、画像のアドレスで指定されたランダムな文字列のソルティハッシュを知る必要があります)。
さらに、イメージ(qr_code_picture)を読み込むときに、イメージのアドレスに含まれるランダム文字列が再度ハッシュされ、Redisに対応するキーがあるかどうかがチェックされます。 そのようなキーがあり、現在のユーザーの識別子が含まれている場合、サイトでの即時認証のための絶対リンクを含むQRコードが作成され、返されます。 それ以外の場合、エラー404が返されます。
ところで、ここで簡単に改善できることを理解していますか?
実行する
ValueErrorが発生
場合があります-Redisにそのようなキーがあるが、その値が10進整数への変換に適していない場合。 try ... exceptを使用するか、 isdigit stringメソッドを使用して解決します。 または、逆に、request.user.idから文字列を取得し、受信したキー値と比較できます。
ハッシュだけでなく、たとえばプレフィックス付きのハッシュを使用することもできます。これは、同様のキーが別の場所で作成されている場合に特に当てはまります。
int(user_id) != request.user.id
実行する
int(user_id) != request.user.id
ValueErrorが発生
int(user_id) != request.user.id
場合があります-Redisにそのようなキーがあるが、その値が10進整数への変換に適していない場合。 try ... exceptを使用するか、 isdigit stringメソッドを使用して解決します。 または、逆に、request.user.idから文字列を取得し、受信したキー値と比較できます。
ハッシュだけでなく、たとえばプレフィックス付きのハッシュを使用することもできます。これは、同様のキーが別の場所で作成されている場合に特に当てはまります。
ここでドメインを取得するには、 django.contrib.sitesを使用します 。 管理インターフェース(/ admin / sites / site /)を介してドメインを指定できます。
サーバーがリバースプロキシ(たとえば、nginx)の背後にあり、SSLを使用している場合、これに関する情報が上流サーバーへのリクエストに含まれていることを確認してください-request.is_secure()が正しい値(このために設定でSECURE_PROXY_SSL_HEADERを定義しますが、プロキシサーバー側でこのヘッダーを設定/削除する必要があることに注意してください-そうしないと、たとえば、サイトがHTTPおよびHTTPS経由でアクセスできる場合、HTTP経由でアクセスするユーザーはrequest.is_secure()が返されるようにこのヘッダーを設定します )Trueに、その安全性の面で悪いです。
はい、Python 2.6以降では、
request.is_secure() and "https" or "http"
代わりに、
request.is_secure() and "https" or "http"
場合は
"https" if request.is_secure() else "http"
記述でき
"https" if request.is_secure() else "http"
。
インスタント認証のリンクをクリックすると、リンクで指定されたハッシュに対応するキーがRedisにあるかどうかが確認されます。 そうでない場合、ユーザーは、QRコードが無効であることを示すメッセージのあるページにリダイレクトされます(この例では、このページに個別の送信は必要ありません)。 存在する場合、Redisのキーが削除され、その後、データベースにこの識別子を持つユーザーが存在するかどうかがチェックされます。 そうでない場合は、再度、QRコードが無効であるというメッセージとともにページにリダイレクトされます。 存在する場合、認証が行われ、ユーザーはサイトのメインページにリダイレクトされます。
urls.pyファイルを追加し、その中にアプリケーションのURLスキームを定義します。
from django.conf.urls import patterns, url from django.views.generic.simple import direct_to_template urlpatterns = patterns('qrauth.views', url( r'^pic/(?P<auth_code>[a-zA-Z\d]{50})/$', 'qr_code_picture', name='auth_qr_code' ), url( r'^(?P<auth_code_hash>[af\d]{40})/$', 'login_view', name='qr_code_login' ), url( r'invalid_code/$', direct_to_template, {'template': 'qrauth/invalid_code.html'}, name='invalid_auth_code' ), url( r'^$', 'qr_code_page', name='qr_code_page' ), )
また、メインのurls.py(ROOT_URLCONFで示されます)を開くことを忘れないでください。作成されたアプリケーションのurls.pyからのurlpatternsをそこに含めてください:
urlpatterns = patterns('', # … url(r'^qr/', include('qrauth.urls')), # … )
ここでテンプレートディレクトリを開き、そこにqrauthディレクトリを追加します。
invalid_code.htmlの例:
{% extends "base.html" %} {% block title %}QR- {% endblock %} {% block content %} <div class="error"> <h1>QR- </h1> <p>QR-, , . , QR- .</p> </div> {% endblock %}
page.htmlの例:
{% extends "base.html" %} {% block title %}QR- {% endblock %} {% block content %} <div class="qr_code"> <h1>QR- </h1> <p> (, ) QR-:</p> <div><img src="{% url auth_qr_code auth_code %}" alt="QR"></div> <p> QR- 5 . QR-, <a href="{% url qr_code_page %}"> </a> .</p> </div> {% endblock %}
実際には、今はブラウザでサイトを開いて確認する必要があります。 QRコードが正常に生成および表示されたら、携帯電話などを使用して、カメラとインターネットでスキャンしてみてください。
モバイルデバイスからの迅速かつ便利な承認のための他のオプションについて質問や意見がある場合は、コメントさせていただきます。
皆さんに幸運を祈り、プログラミングをお楽しみください!
あなたに幸せな夏を! :)