[Dd]enzow(ill)? with DB and Python

DBとか資格とかPythonとかの話をつらつらと

普通のDjangoでlogin用のAPIを作る

普段は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で渡ってくるusernamepasswordで認証したかったのでjson.loadsしてパラメータを取り出します。外部から叩く予定だったのでcsrf_exemptでCSRFは外しています。

Djangoではdjango.contrib.auth.authenticateを使用することで、passwordをちゃんと検証して該当するユーザが存在するかをチェックしてくれます。usernamepasswordが正しければ認証済の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関数で引き剥がすだけです。logoutdjango.contrib.auth.views.logoutという関数ベースのViewが<中略>注意してください。

まとめ

Djangoでセッションにログイン情報を付与する時はdjango.contrib.auth.authenticateで認証済のユーザを取得し、django.contrib.auth.loginでセッション紐づけましょう。