将经过 REST 化的 Django 的 JWT 认证完全交给 dj_rest_auth

到目前为止的经过

    1. 在本地搭建了Ubuntu Server,

 

    1. 安装了Docker Compose,

 

    1. 使用Docker Compose构建了Django+MySQL+nginx的开发环境,

 

    1. 尝试在AWS Fargate上运行Django,但失败了。

 

    1. 通过继承AbstractBaseUser创建了一个自定义用户,可以通过电子邮件进行登录。

 

    通过使用django-environ和环境变量设置,将在Git上公开的敏感变量隐藏起来。

以下是 GitHub 存储库链接:https://github.com/hajime-f/octave。

这次想要做的事情

我們從上上次開始,當時我們使得自訂用戶能夠透過電子郵件登錄。

我想要做的两件事是:
– 引入 Django REST Framework
– 使用 dj_rest_auth 实现 JWT 认证。

如果有人说「REST是什么东西」,请阅读这篇文章。我从零开始研究了一下REST API。

如果有人问「JWT(ジョット)认证是什么?」,以下内容可能会有所帮助。
关于JWT认证和流程的简明解释。

步骤

    1. 在运行Django的容器中安装包

 

    1. 编辑settings.py文件

 

    1. 在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的完整内容。

修改 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

将uuid作为用于标识用户的主键,因此需要进行相应的设置。

此外,如前文所述,为了实现仅通过电子邮件地址(不使用用户名)进行认证,系统中包含了多项相关设置。

在 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框架具有自己的静态文件,因此让我们将这些静态文件收集到基础目录中。

$ docker-compose -f docker-compose.dev.yml run python ./manage.py collectstatic

确认动作

请用浏览器访问 http://[开发环境的IP地址]:[开发环境的端口号]/dj-rest-auth/login/,并确保可以使用测试用户登录。

スクリーンショット 2021-01-03 22.51.38.png

如果以这种方式返回访问令牌,那就意味着成功。

即使从终端执行curl命令,也可以查看结果。

$ curl \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"email": "test@test.com", "password": "test123456"}' \
  http://[開発環境のIPアドレス]:[開発環境のポート番号]/dj-rest-auth/login/
{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGci...",
"user":{"pk":"de0e84a7-8396-497e-aa07-e143cc0a2811",
"email":"test@test.com",
"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”的异常,甚至登录功能都无法正常工作。

スクリーンショット 2021-01-04 18.17.41.png

我正在烦恼中。为什么呢。
我贴上以下的错误日志,请知道的人告诉我。

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.

请参考

    • dj-rest-auth の公式ドキュメント

 

    simple JWT の公式ドキュメント