はじめに
5/18、琴葉ちゃんの日!! nikkieです。
Django REST framework(以下、DRF)ネタです。
私、何もわかっていませんでした...
目次
- はじめに
- 目次
- Authorizationヘッダ Token で認証できるエンドポイント
- 『現場で使える Django REST Framework の教科書』より
- 脱線:Authorizationヘッダ
- DRFのドキュメントより
- djoserはエンドポイント追加
- 終わりに
Authorizationヘッダ Token で認証できるエンドポイント
先日djoserを復習しました。
djoserリポジトリにあるサンプルアプリtestprojectを動かしています
% curl http://127.0.0.1:8088/auth/token/login/ --data 'username=djoser&password=alpine12'
{"auth_token":"0d0bca572490495255f1f626d96bfb61ffaba86a"}
% curl -L http://127.0.0.1:8088/auth/users/me/ -H 'Authorization: Token 0d0bca572490495255f1f626d96bfb61ffaba86a'
{"email":"","id":1,"username":"djoser"}
ここではAuthorizationというヘッダに「Token ...」という形式で指定しています。
トークンを払い出して使うAPIの場合、Authorizationヘッダは「Bearer ...」という形式をよく見かけますよね。
APIのクライアントがBearerと指定できるようにするのをどうやるのか調べました。
『現場で使える Django REST Framework の教科書』より
akiyokoさんの教科書シリーズには大変お世話になっています。
7.4でトークン認証を扱っていて、次の設定で'Authorization: Bearer ...'で認証できると書かれています。
# settings.py INSTALLED_APPS = [ # ... "rest_framework", "rest_framework.authtoken", "djoser", ] REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": [ "rest_framework.authentication.TokenAuthentication", ], }
urls.pyはdjoserのtestprojectに寄せました
# プロジェクトの urls.py urlpatterns = [ path("auth/", include("djoser.urls.base")), path("auth/", include("djoser.urls.authtoken")), ]
ところが、どうにもBearerではなくTokenのようで、私には未解決の課題となっていました1。
% curl http://127.0.0.1:8088/auth/token/login/ --data 'username=djoser&password=alpine12'
{"auth_token":"42850e913ae42209670b9df3f584103923880cfb"}
% curl -L http://127.0.0.1:8088/auth/users/me/ -H 'Authorization: Bearer 42850e913ae42209670b9df3f584103923880cfb'
{"detail":"Authentication credentials were not provided."}
% curl -L http://127.0.0.1:8088/auth/users/me/ -H 'Authorization: Token 42850e913ae42209670b9df3f584103923880cfb'
{"email":"","id":1,"username":"djoser"}
脱線:Authorizationヘッダ
この機にMDNのドキュメントを見てみました。
認証方式(HTTP 認証 - HTTP | MDN)
また、レスポンスの「WWW-Authenticate」ヘッダを知りました。
https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/WWW-Authenticate
上でBearerトークンを使ったcurlに-vを指定すると、対応しているのはTokenと情報がありました
< WWW-Authenticate: Token
DRFのドキュメントより
TokenAuthentication
djoserとDRFの役割が分かれていることを私が認識できていなかったために錯綜しました。
DRFのドキュメントに記載がありました。
TokenAuthentication
https://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication
Tokenの代わりにBearerを使いたい場合への言及もありました
If you want to use a different keyword in the header, such as Bearer, simply subclass
TokenAuthenticationand set thekeywordclass variable.
意訳 TokenAuthenticationを継承したクラスで、クラス変数keywordを設定する
AuthorizationヘッダをBearerにする設定例
TokenAuthenticationを継承したクラスを用意します(プロジェクトの中のauthentication.py)
from rest_framework.authentication import TokenAuthentication class BearerTokenAuthentication(TokenAuthentication): keyword = "Bearer"
settings.pyでREST_FRAMEWORKの指定を変更します
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
- "rest_framework.authentication.TokenAuthentication",
+ "authentication.BearerTokenAuthentication",
],
}
(settings.pyと同じディレクトリにあるauthentication.pyの中のクラスを指定しています)
これで、Bearerに続けてトークンを指定するように変わりました!
% curl http://127.0.0.1:8088/auth/token/login/ --data 'username=djoser&password=alpine12'
{"auth_token":"5ca5887fd6e1113a162e76a329b13f054a495930"}
% curl -L http://127.0.0.1:8088/auth/users/me/ -H 'Authorization: Bearer 5ca5887fd6e1113a162e76a329b13f054a495930'
{"email":"","id":1,"username":"djoser"}
% curl -L http://127.0.0.1:8088/auth/users/me/ -H 'Authorization: Token 5ca5887fd6e1113a162e76a329b13f054a495930'
{"detail":"Authentication credentials were not provided."}
djoserはエンドポイント追加
『現場で使える Django REST Framework の教科書』にはdjoserについて
Webアプリケーションで利用可能なREST APIの認証系エンドポイントを簡単に追加することができるDjangoパッケージ
と書かれています(p.112)
djoser.urls.baseのおかげで
https://github.com/sunscrapers/djoser/blob/2.2.2/djoser/urls/base.py
/users/にPOSTしてユーザを作ったり/users/me/にGETして自分の情報を取得したり
できています。
そして、djoser.urls.authtokenによって、/token/login/ と /token/logout/ が追加されています
https://github.com/sunscrapers/djoser/blob/2.2.2/djoser/urls/authtoken.py
終わりに
AuthorizationヘッダでBearerと書けるようにする中で、ごっちゃにしていたDRFとdjoserの役割が整理されました。
✍️Authorizationヘッダ中のTokenをBearerに変えるには、DRFのTokenAuthenticationを継承してkeywordを設定する