18
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

脱・とりあえず動く[DRF JWT編]

Posted at

課題

「業務で使っているけど、よく知らない。けどとりあえず動いている」ということが非常に多いので、調べたこと、試したことをまとめていこうと思います。
今回はDjango REST framework JWT編です。

そもそもJWTって?

参考
https://tools.ietf.org/html/rfc7519
https://jwt.io

  • JSON形式で認証・証明するための仕様
  • Header.Payload.Signatureからなる
  • Headerにはトークンの情報と暗号化の情報、Payloadにはエンティティ(ユーザー)の情報、Signatureには署名が入っている
  • これらをくっつけて暗号化したものを渡す

流れとしては、

  • ログイン成功するとサーバーからJWTが返される
  • 以降、リクエストのAuthorizationに受け取ったJWTを含めると、制限されている処理が許可される

DRFでどうやって使うの?

Django REST Framework JWTを利用します。

this module only generates authentication tokens that will verify the user who is requesting one of your DRF protected API resources

(引用元:https://getblimp.github.io/django-rest-framework-jwt/)
「DRFで認証が必要なAPIでユーザー認証するために必要なトークンを発行します」

実際に試してみる

参考:http://racchai.hatenablog.com/entry/2016/05/08/070000

インストール
pip install djangorestframework-jwt

プロジェクト作成
django-admin startproject sample

マイグレーション
python manage.py migrate

ユーザー追加
python manage.py createsuperuser

settting.pyに追加

setting.py
REST_FRAMEWORK = { 
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),  
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),  
}

設定の内容(参考:http://www.django-rest-framework.org/api-guide/settings/)
DEFAULT_PERRMISSION_CLASSES:認証の設定。IsAuthenticatedは認証されているユーザのみ許可。
DEFAULT_AUTHENTICATION_CLASSES: 認証はどのクラスを使うかの設定。JWTを使う。

url.pyに追加

url.py
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
    path('obtain_jwt_token/', obtain_jwt_token)
]

サーバー起動
python manage.py runserver

とりあえずPOSTしてみる。
curl -X POST http://localhost:8000/obtain_jwt_token/
怒られた。
{"username":["This field is required."],"password":["This field is required."]}

さっき作成したユーザ情報を追加してもう一度POST。
curl -X POST http://localhost:8000/obtain_jwt_token/ -d "username=<ユーザー名>&password=<パスワード>"

返ってきた!
{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2(省略).kNRNxQr-zWCykMPmA(省略)"}
Header.Payload.Signature形式になっています。

もっと試してみる

発行→なんらかの操作が認証されることを確認してみます。
参考:http://www.django-rest-framework.org

アプリの追加
python manage.py startapp sample_app

setting.pyの追加

setting.py
# 差分のみ
# DRFを使えるようにする
INSTALLED_APP = [
    'rest_framework'
]

REST_FRAMEWORK = { 
    'DEFAULT_PERMISSION_CLASSES': (
        # 確認のために認証方法を変更する
        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
    ),  
}

serializer,viewset,urlsの編集

sample_app/serializer.py
from django.contrib.auth.models import User
from rest_framework import serializers

class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'is_staff')
sample_app/viewset.py
from rest_framework import viewsets
from .serializer import UserSerializer
from django.contrib.auth.models import User

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
sample_app/urls.py
from rest_framework import routers
from .views import UserViewSet

router = routers.DefaultRouter()
router.register(r'users', UserViewSet)

urlpatterns = router.urls

sample直下のurlsに追加

sample/urls.py
# 差分のみ
from django.urls import path, include

urlpatterns = [
    path('sample_app/',include('sample_app.urls'))
]

これでユーザーへのAPIができました。
確認します。
http://localhost:8000/sample_app/users/

[{"url":"http://localhost:8000/api/users/<ユーザーID>/","username":"<ユーザー名>","email":"<メールアドレス>","is_staff":true}]
sample_app/users/へGETを投げたので、ユーザーのリストが取得できました。

では、認証の設定を戻してもう一度。

setting.py
# 差分のみ
REST_FRAMEWORK = { 
    'DEFAULT_PERMISSION_CLASSES': (
        # 元に戻す
        'rest_framework.permissions.IsAuthenticated',
    ),  
}

http://localhost:8000/sample_app/users/

トークンがないので怒られます。
{"detail":"Authentication credentials were not provided."}

では、トークンを発行し、ヘッダーに追加してからもう一度。
curl http://localhost:8000/obtain_jwt_token/ -X POST -d "username=<ユーザー名>&password=<パスワード>"

{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2V(省略).67Gwc-Wsm(省略)"}

http://localhost:8000/sample_app/users/ -H "Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2V(省略).67Gwc-Wsm(省略)

[{"url":"http://localhost:8000/api/users/<ユーザーID>/","username":"<ユーザー名>","email":"<メールアドレス>","is_staff":true}]
先ほどと同じデータが取得できました!

終わりに

公式ドキュメントや参考ページの手順を追うだけになってしまいましたが、理解が進みました。
アウトプットって大事ですね。
DRF JWTの前にDRF自体もなんとなく触っているだけなので、そっちも調べてみようと思っています。
ありがとうございました。

18
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?