REST 化した Django の JWT 認証を dj_rest_auth に丸投げする
これまでの経緯
GitHub のレポジトリはこちら:https://github.com/hajime-f/octave
今回やりたいこと
前々回で、カスタムユーザーで E-mail ログインができるようになったところから始めます。
今回やりたいことは、
- Django REST Framework を導入する
- dj_rest_auth を使って JWT 認証を実現する
の2つ。
「REST ってなんやねん」という人は、こちらの記事を読みましょう。
0からREST APIについて調べてみた
「JWT(ジョット)認証ってなんやねん」という人は、このあたりが参考になります。
JWT認証と流れのやわらかい解説
手順
- Django を動かすコンテナにパッケージをインストールする
-
settings.py
を編集する
-
urls.py
でルーティングを設定する
- 静的ファイルをベースディレクトリに集める
1. パッケージをインストールする
settings.py
を編集するurls.py
でルーティングを設定するまずは REST Framework のパッケージと、JWT 認証用のパッケージをインストールします。コンテナにこれらをインストールするために、requirements.txt
を編集します。なお、パスは docker-compose.dev.yml
があるプロジェクトディレクトリからの相対パスです。
Django==3.1.4
uwsgi==2.0.18
mysqlclient==1.4.6
django-environ==0.4.5
djangorestframework==3.12.2 # 追加
djangorestframework-simplejwt==4.6.0 # 追加
dj-rest-auth==2.1.2 # 追加
編集したらビルドしておきましょう。
$ make dev # docker-compose -f docker-compose.dev.yml build と同じ
Makefile
の全内容は、以前の記事を読んでね。
2. settings.py
を編集する
公式ドキュメントに書いてあるとおりに、settings.py
を編集します。
INSTALLED_APPS = [
・・・
'django.contrib.sites', # 追加
# 3rd party apps
'rest_framework', # 追加
'rest_framework.authtoken', # 追加
'dj_rest_auth', # 追加
#My applications
'users',
]
# 以下すべて追加
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'dj_rest_auth.jwt_auth.JWTCookieAuthentication',
)
}
SITE_ID = 1
REST_USE_JWT = True
JWT_AUTH_COOKIE = 'user'
AUTH_USER_MODEL = 'users.User'
SIMPLE_JWT = {
'USER_ID_FIELD': 'uuid',
}
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ユーザーを特定する primary key を uuid としたので、そのための設定が必要です。
また、以前の記事のとおり、メールアドレスのみ(ユーザーネームは使わない)で認証できるようにしたいので、そのための設定がいろいろと入ってます。
3. urls.py
でルーティングを設定する
これも公式ドキュメントに書いてあるとおりに、urls.py
でルーティングを設定します。
from django.contrib import admin
from django.urls import path
from django.urls import include # 追加
urlpatterns = [
path('admin/', admin.site.urls),
path('dj-rest-auth/', include('dj_rest_auth.urls')), # 追加
]
4. 静的ファイルをベースディレクトリに集める
REST Framework は独自の静的ファイルを持っているので、ベースディレクトリにその静的ファイルを集めておきましょう。
$ docker-compose -f docker-compose.dev.yml run python ./manage.py collectstatic
動作確認
ブラウザで http://[開発環境のIPアドレス]:[開発環境のポート番号]/dj-rest-auth/login/
にアクセスし、テストユーザーでログインできることを確認します。
こんな感じでアクセストークンが返ってきたら成功です。
端末から curl
コマンドを叩いても、結果を確認できます。
$ curl \
-X POST \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "password": "test123456"}' \
http://[開発環境のIPアドレス]:[開発環境のポート番号]/dj-rest-auth/login/
{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGci...",
"user":{"pk":"de0e84a7-8396-497e-aa07-e143cc0a2811",
"email":"[email protected]",
"first_name":"テスト",
"last_name":"テスト"}}%
いま苦しんでいるバグ
(追記)このバグは、公式に質問したら解決できました。
本当は、こうすればユーザー登録も丸投げできるはずなんですね。
Django==3.1.4
uwsgi==2.0.18
mysqlclient==1.4.6
django-environ==0.4.5
djangorestframework==3.12.2
djangorestframework-simplejwt==4.6.0
dj-rest-auth==2.1.2
django-allauth==0.44.0 # さらに追加
INSTALLED_APPS = [
・・・
'django.contrib.sites',
# 3rd party apps
'rest_framework',
'rest_framework.authtoken',
'allauth', # さらに追加
'allauth.account', # さらに追加
'dj_rest_auth',
'dj_rest_auth.registration', # さらに追加
#My applications
'users',
]
・・・
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_EMAIL_REQUIRED = True # さらに追加
ACCOUNT_UNIQUE_EMAIL = True # さらに追加
ACCOUNT_EMAIL_VERIFICATION = 'mandatory' # さらに追加
urlpatterns = [
path('admin/', admin.site.urls),
path('dj-rest-auth/', include('dj_rest_auth.urls')),
path('dj-rest-auth/registration/', include('dj_rest_auth.registration.urls')), # さらに追加
]
これは公式ドキュメントに書いてあるとおりなのですが、カスタムユーザーを使っているせいか「EmailAddress matching query does not exist」の例外が出て、さっきまで動いていたログインすらうまく動きません。
絶賛悩み中。なんでだ。
以下にエラーログを貼っておくので、誰か分かる人、教えて。
Environment:
Request Method: POST
Request URL: http://127.0.0.1:8081/dj-rest-auth/login/
Django Version: 3.1.4
Python Version: 3.9.1
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'rest_framework',
'rest_framework.authtoken',
'allauth',
'allauth.account',
'allauth.socialaccount',
'dj_rest_auth',
'dj_rest_auth.registration',
'users',
'orchestra']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 179, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/django/views/generic/base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/django/views/decorators/debug.py", line 89, in sensitive_post_parameters_wrapper
return view(request, *args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/dj_rest_auth/views.py", line 48, in dispatch
return super(LoginView, self).dispatch(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/dj_rest_auth/views.py", line 138, in post
self.serializer.is_valid(raise_exception=True)
File "/usr/local/lib/python3.9/site-packages/rest_framework/serializers.py", line 220, in is_valid
self._validated_data = self.run_validation(self.initial_data)
File "/usr/local/lib/python3.9/site-packages/rest_framework/serializers.py", line 422, in run_validation
value = self.validate(value)
File "/usr/local/lib/python3.9/site-packages/dj_rest_auth/serializers.py", line 131, in validate
self.validate_email_verification_status(user)
File "/usr/local/lib/python3.9/site-packages/dj_rest_auth/serializers.py", line 112, in validate_email_verification_status
email_address = user.emailaddress_set.get(email=user.email)
File "/usr/local/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 429, in get
raise self.model.DoesNotExist(
Exception Type: DoesNotExist at /dj-rest-auth/login/
Exception Value: EmailAddress matching query does not exist.
参考
Author And Source
この問題について(REST 化した Django の JWT 認証を dj_rest_auth に丸投げする), 我々は、より多くの情報をここで見つけました https://qiita.com/hajime-f/items/0b42fa3233e41a0f691d著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .