開発日記

出退勤アプリのDjangoの認証をJWTに変更!

こんにちは、MSKです。
出退勤のバックエンドを作ったので、フロント側を作っていましたが認証関係でSessionIDを取得しないと作れない部分があり、dj_rest_authをやめてJWTに変更します。

関連する記事は以下になります。
出退勤の時間を記録するWebアプリの作り始め!
出退勤時間を記録するアプリのAPIを作る! 
出退勤時間を記録するアプリのユーザー登録と認証を実装する! 
Djangoの開発環境をDockerで構成してみる!
出退勤を記録するアプリをDockerで動かす!
出退勤アプリのDjangoの認証をJWTに変更!<- この記事はここ!

dj_rest_authだとできなかったこと

出退勤のアプリでは出退勤の時間とユーザー情報を紐づけています。
出退勤のAPIを叩く時に、ログインしているユーザーのIDが必要になります。

実現したかったことはログイン時に渡されるkeyを使ってユーザー情報(ユーザーのID)を取得するというものです。

dj_rest_authの機能を使ってユーザーのIDを取得しようとするとsession IDが必要でした。
(postmanからsesssion IDを消去するとkeyを指定していてもユーザー情報はとれません・・・)

React、またはJavaScriptでsession IDを取得する方法を検索しているといくつかの記事がでてきました。

その中で、SPAで作る場合はsession IDを扱わない方がよいという記事が多数・・・
先人の言うことは聞いておこうと思ってsession IDを取得することはやめました!

ユーザー全体を取得することはできるので、ユーザー全体を取得して、usernameで検索かけて取得することも考えました。

今回は自分のために作るのでユーザーは基本自分だけなので、「まぁ、しょうがないかな」とも考えましたが、この後サービスをどんどん作っていきたいと考えているのであんまり妥協をしないことにしました!

ということで、dj_rest_authを使わないことにしました。
dj_rest_authと同じように認証ができて、ログインしているユーザー情報が取れるdj_rest_authの代わりを探す必要があります。

偶然にもsession IDの取得方法を探している時にsession IDを使うのではなくてJWT(JSON Web Token)を使うべしという記事もあったのでJWTについて調べて、そっちに切り替えることにしました。

JWTを使ってみる

djoserとSimple JWTをインストールします。
JWTを使えるようにsettings.pyを次のように変更します。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'corsheaders',
    'api.apps.ApiConfig',
    'rest_framework',
    'djoser',
]
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
}

SIMPLE_JWT = {
    'AUTH_HEADER_TYPES': ('JWT',),
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30),
}

認証機能を使えるようにurls.pyを次のように変更します。

path('authen/',include('djoser.urls.jwt')),

あとはrunserverして動作を確認します。

JWTの動作確認

postmanでhttp://127.0.0.1:8000/authen/jwt/createにPOSTします。

refreshとaccessのトークンが返ってきます。

このaccessトークンをHeaderのAuthorizationに「JWT accessトークン」の形で使い認証を行います。

accessトークンは設定した時間で期限切れとなるので期限が切れたらrefreshトークンを用いて、http://127.0.0.1/authen/jwt/refreshにPOSTすることでaccessトークンの更新をすることができます。

ログインユーザーの情報を取得する

やりたかったログインユーザー情報を取得するためのAPIを作成します。

views.pyに次のクラスを追加します。

class LoginUserView(generics.RetrieveUpdateAPIView):
    serializer_class = UserSerializer
    def get_object(self):
        return self.request.user #ログインしているユーザーを返す
    #PUTを無効化
    def update(self, request, *args, **kwargs):
        response = {"message": 'PUT method is not allowed'}
        return Response(response, status=status.HTTP_400_BAD_REQUEST)

RetrieveUpdateAPIViewは特定のオブジェクトを検索して返す機能に使います。
今回はログインしているユーザーを返します。

urls.pyに登録して動作確認します。

path('loginuser/',LoginUserView.as_view(),name='loginuser'),

runserverして動作を確認します。
まず、postmanでhttp://127.0.0.1:8000/authen/jwt/createにPOSTしてaccessトークンを取得します。
その後、HeaderのAuthorizationに取得したaccessトークンをセットして、http://127.0.0.1:8000/loginuser/にGETを行います。

次のようにユーザーIDとユーザー名が返されました!

最後に

ログインしているユーザーの情報を取るということが認証をJWTに変えて実現することができました。

ユーザー情報も取れるようになったのでフロント側から出退勤のAPIを呼ぶことができます。

次からReactでフロントを作って行きます。

最後までご覧いただき、ありがとうございました。
「出退勤アプリのDjangoの認証をJWTに変更!」でした。

ABOUT ME
MSK
九州在住の組み込み系エンジニアです。 2児の父親でもあります。 数学やプログラミングが趣味です。 最近RustとReact、結び目理論と曲面結び目理論にはまっています。