View on GitHub

サインアウトビューの作成

Home

サインアウトビューの作成

設定ファイル

src/backend/config/settings/base.py

......
INSTALLED_APPS = [
    ......
    'django_filters',
    'rest_framework_simplejwt.token_blacklist',  # <- 追加
]
......
SIMPLE_JWT = {
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=60),
    "REFRESH_TOKEN_LIFETIME": timedelta(days=7),
    "AUTH_HEADER_TYPES": ("Bearer",),

    "SIGNING_KEY": os.environ.get("JWT_SIGNING_KEY", SECRET_KEY),

    "ROTATE_REFRESH_TOKENS": False,    # <- 追加
    "BLACKLIST_AFTER_ROTATION": True,  # <- 追加
}

マイグレーション

(recsys_full) backend$ python manage.py makemigrations
No changes detected

(recsys_full) backend$ python manage.py migrate
Operations to perform:
  Apply all migrations: accounts, admin, auth, contenttypes, online, sessions, token_blacklist
Running migrations:
  Applying token_blacklist.0001_initial... OK
  Applying token_blacklist.0002_outstandingtoken_jti_hex... OK
  Applying token_blacklist.0003_auto_20171017_2007... OK
  Applying token_blacklist.0004_auto_20171017_2013... OK
  Applying token_blacklist.0005_remove_outstandingtoken_jti... OK
  Applying token_blacklist.0006_auto_20171017_2113... OK
  Applying token_blacklist.0007_auto_20171017_2214... OK
  Applying token_blacklist.0008_migrate_to_bigautofield... OK
  Applying token_blacklist.0010_fix_migrate_to_bigautofield... OK
  Applying token_blacklist.0011_linearizes_history... OK
  Applying token_blacklist.0012_alter_outstandingtoken_user... OK
  Applying token_blacklist.0013_alter_blacklistedtoken_options_and_more... OK

テーブルの確認

recsys_full=# \dt
                       List of relations
 Schema |                 Name                 | Type  | Owner
--------+--------------------------------------+-------+-------
...(略)...
 public | token_blacklist_blacklistedtoken     | table | rsl
 public | token_blacklist_outstandingtoken     | table | rsl
(13 rows)

シリアライザ

src/backend/api/accounts/serializers.py

from rest_framework import serializers
from rest_framework_simplejwt.tokens import RefreshToken, TokenError  # <- TokenErrorを追加
......
# ↓追加
class SignOutSerializer(serializers.Serializer):
    refresh = serializers.CharField()

    def validate(self, attrs):
        self.token = attrs["refresh"]
        return attrs

    def save(self, **kwargs):
        try:
            token = RefreshToken(self.token)
            token.blacklist()
        except TokenError:
            pass
# ↑追加

ビュー

src/backend/api/accounts/views.py

from rest_framework.views import APIView
from rest_framework.permissions import AllowAny, IsAuthenticated  # <- IsAuthenticatedを追加
from rest_framework.response import Response
from rest_framework import status

from .serializers import SignUpSerializer, SignInSerializer, SignOutSerializer  # <- SignOutSerializerを追加
......
# ↓追加
class SignOutView(APIView):
    permission_classes = (IsAuthenticated,)

    def post(self, request):
        serializer = SignOutSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'detail': 'Successfully logged out.'}, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# ↑追加

URL マッピング

src/backend/api/accounts/urls.py

from django.urls import path
from .views import SignUpView, SignInView, SignOutView  # <- SignOutViewを追加

urlpatterns = [
    path("signup/", SignUpView.as_view(), name="accounts-signup"),
    path("signin/", SignInView.as_view(), name="accounts-signin"),
    path("signout/", SignOutView.as_view(), name="accounts-signout"),  # <- 追加
]

実行確認

サインインビューの作成の手順にしたがってサインインし、アクセストークンとリフレッシュトークンを取得してください。取得したトークンを用いて、バックエンドサーバが起動している状態で、下記コマンドを実行してください。

$ curl -X POST http://localhost:8000/api/accounts/signout/ \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -d '{"refresh": "<REFRESH_TOKEN>"}'

{"detail":"Successfully logged out."}

上記のように{"detail":"Successfully logged out."}と表示されれば成功です。