サインアウトビューの作成
設定ファイル
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."}と表示されれば成功です。