普段はDjangoで普通にWEBアプリを作っていますが、別のクライアントアプリから認証する必要がでたので、login用のAPIを作ることになったのですが、django api login
とかでググるとDjango REST Frameworkでの話ばかりになったのでメモ程度に。
環境
- django 1.11
- python 3.6
コード
こんな感じになりました。
login
import json from django.contrib.auth import authenticate, login, logout from django.http import JsonResponse from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt from django.views.generic import View @method_decorator(csrf_exempt, name='dispatch') class LoginAPIView(View): def post(self, request): params = json.loads(request.body) username = params['username'] password = params['password'] user = authenticate(username=username, password=password) if user is not None: login(request, user) return JsonResponse({'is_authenticated': True}) return JsonResponse({'is_authenticated': False}, status=403)
とりあえず、JSONで渡ってくるusername
とpassword
で認証したかったのでjson.loads
してパラメータを取り出します。外部から叩く予定だったのでcsrf_exempt
でCSRFは外しています。
Djangoではdjango.contrib.auth.authenticate
を使用することで、password
をちゃんと検証して該当するユーザが存在するかをチェックしてくれます。username
とpassword
が正しければ認証済のuser
モデルを戻してくれます。
なお、ここで取得されるuser
モデルのインスタンスはUser.objects.get(pk=xx)
で取得されるものとは若干ことなり、認証に使用したバックエンドの情報が追加の属性としてセットされています。
Using the Django authentication system | Django documentation | Django
その後、django.contrib.auth.login
関数にrequest
と取得されたuser
を渡すことでセッションに認証済みのユーザ情報を紐づけます。これをしないと、ログイン済状態にはなりません。
ちなみに、1.11では非推奨ながらdjango.contrib.auth.views.login
という関数ベースのViewが存在し、そちらを誤ってimport
して1時間を溶かしました・・・。現在はdjango.contrib.auth.views.LoginView
というクラスベースビューで置き換えられているようです。
logout
@method_decorator(csrf_exempt, name='dispatch') class LogoutAPIView(View): def post(self, request): logout(request) return JsonResponse({'is_authenticated': False})
logoutはシンプルです。request
というかセッションに紐付いているユーザ情報をdjango.contrib.auth.logout
関数で引き剥がすだけです。logout
もdjango.contrib.auth.views.logout
という関数ベースのViewが<中略>注意してください。
まとめ
Djangoでセッションにログイン情報を付与する時はdjango.contrib.auth.authenticate
で認証済のユーザを取得し、django.contrib.auth.login
でセッション紐づけましょう。