課題
「業務で使っているけど、よく知らない。けどとりあえず動いている」ということが非常に多いので、調べたこと、試したことをまとめていこうと思います。
今回は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に追加
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に追加
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の追加
# 差分のみ
# DRFを使えるようにする
INSTALLED_APP = [
'rest_framework'
]
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
# 確認のために認証方法を変更する
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
),
}
serializer,viewset,urlsの編集
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')
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
from rest_framework import routers
from .views import UserViewSet
router = routers.DefaultRouter()
router.register(r'users', UserViewSet)
urlpatterns = router.urls
sample直下のurlsに追加
# 差分のみ
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を投げたので、ユーザーのリストが取得できました。
では、認証の設定を戻してもう一度。
# 差分のみ
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自体もなんとなく触っているだけなので、そっちも調べてみようと思っています。
ありがとうございました。