読者です 読者をやめる 読者になる 読者になる

らっちゃいブログ

日々の学びと気づきを発信するブログ

DjangoでJWTを使ったトークン認証を実装する

スポンサーリンク

JWT とは

Json Web Token の略。一言でいってしまうとJSONに署名したもの。こちらの記事で詳しく解説されています。

JSON Web Token の効用 - Qiita

はじめに

さっそく環境を作っていきます。最初はお決まりのプロジェクト作成です。

詳しい手順と説明はこちらの記事をご参照ください。

racchai.hatenablog.com

Lightweight Django

Lightweight Django

ではプロジェクトを作成します。

$ django-admin startproject racchai
$ cd racchai

今回は認証を扱うので、データベースとユーザーも作成しておきます。

$ ./manage.py migrate                                                                                                                                  │
Operations to perform:                                                                                                                                                                     │
  Synchronize unmigrated apps: staticfiles, messages                                                                                                                                       │
  Apply all migrations: admin, contenttypes, auth, sessions                                                                                                                                │
Synchronizing apps without migrations:                                                                                                                                                     │
  Creating tables...                                                                                                                                                                       │
    Running deferred SQL...                                                                                                                                                                │
  Installing custom SQL...                                                                                                                                                                 │
Running migrations:                                                                                                                                                                        │
  Rendering model states... DONE                                                                                                                                                           │
  Applying contenttypes.0001_initial... OK                                                                                                                                                 │
  Applying auth.0001_initial... OK                                                                                                                                                         │
  Applying admin.0001_initial... OK                                                                                                                                                        │
  Applying contenttypes.0002_remove_content_type_name... OK                                                                                                                                │
  Applying auth.0002_alter_permission_name_max_length... OK                                                                                                                                │
  Applying auth.0003_alter_user_email_max_length... OK                                                                                                                                     │
  Applying auth.0004_alter_user_username_opts... OK                                                                                                                                        │
  Applying auth.0005_alter_user_last_login_null... OK                                                                                                                                      │
  Applying auth.0006_require_contenttypes_0002... OK                                                                                                                                       │
  Applying sessions.0001_initial... OK

$ ./manage.py createsuperuser
Username (leave blank to use 'kon'): racchai
Email address: jwt@racchai.com
Password: racchai
Password (again): racchai
Superuser created successfully.

何度やっても楽ちんですね。

トークンを取得してみる

今回は django-rest-framework-jwt を使うのでインストールしておきます。

$ pip install djangorestframework-jwt

インストールができたらracchai/settings.py に以下を追記します。

REST_FRAMEWORK = { 
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),  
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),  
    'NON_FIELD_ERRORS_KEY': 'detail',
    'TEST_REQUEST_DEFAULT_FORMAT': 'json'
}

お次は racchai/urls.py を以下のように編集。

+ from rest_framework_jwt.views import obtain_jwt_token

urlpatterns = [
+ url(r'^jwt-token', obtain_jwt_token),
]

基本設定は以上です。あっという間ですね。では開発サーバーを起動してトークンを取得してみましょう。

$ ./manage.py runserver
$ curl http://localhost:8000/jwt-token -d "username=racchai&password=racchai"
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InJhY2NoYWkiLCJ1c2VyX2lkIjoxLCJlbWFpbCI6Imp3dEByYWNjaGFpLmNvbSIsImV4cCI6MTQ2MTY1MzY0N30.UBZrYz79xeI25-Uufmh2zdwZXXzHjamh9rHeOS2Fuqk"}

無事取得できました。簡単すぎて本当に動いてるのか疑いたくなりますね。念のためパスワードを間違えてみましょう。

$ curl http://localhost:8000/jwt-token -d "username=racchai&password=jwt"
{"detail":["Unable to login with provided credentials."]}

ちゃんと認証失敗しました。安心してください、動いてます。

トークンを使って認証が必要なAPIを実行してみる

まずは認証が必要なAPIを用意します。django-rest-framework-jwt を使っているのですから、APIdjango-rest-framework で作ることにします。

django-rest-framework の初期設定についてはこちらの記事で紹介しています。

racchai.hatenablog.com

次は、ログインユーザー名で返事するだけのAPIを作成しましょう。

racchai/views.py

from rest_framework.generics import GenericAPIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status

class PingViewSet(GenericAPIView):
    permission_classes = (IsAuthenticated,)

    def get(self, request, format=None):
        return Response(data={'username': request.user.username}, status=status.HTTP_200_OK)

APIが作成できたら racchai/urls.py を以下のように編集します。

from django.conf.urls import url
from rest_framework_jwt.views import obtain_jwt_token
+ from racchai import views

urlpatterns = [
    url(r'^jwt-token', obtain_jwt_token),
+   url(r'^ping', views.PingViewSet.as_view()),
]

準備ができたら作成したAPIにアクセスしてみましょう。

$ curl http://localhost:8000/ping
{"detail":"Authentication credentials were not provided."}

認証情報が指定されてないと怒られてしまいました。では JWT トークンをリクエストに乗せて再度トライ。

$ curl http://localhost:8888/ping  -H "Authorization: JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InJhY2NoYWkiLCJ1c2VyX2lkIjoxLCJlbWFpbCI6Imp3dEByYWNjaGFpLmNvbSIsImV4cCI6MTQ2MTY1MzY0N30.UBZrYz79xeI25-Uufmh2zdwZXXzHjamh9rHeOS2Fuqk"
{"username":"racchai"}

無事認証が通ってログインユーザーの情報を取得できていますね!

まとめ

django-rest-framework-jwt を使うことで、一瞬でトークンベースの認証を実現することができました。携帯アプリと連携する際には重宝する機能だと思いますので、ぜひご活用ください。

Pythonプロフェッショナルプログラミング 第2版

Pythonプロフェッショナルプログラミング 第2版