概要
DjangoにGraphQLサーバーを構築し、JWT認証を実装を紹介します。
Djangoのユーザで認証できるようにし、リフレッシュトークンはDBに保存しすぐ無効化できるように設定します。
また、一度使用したリフレッシュトークンは無効化し、再度利用できないように設定します。
別サーバーからアクセスすることを想定し、CORSの設定も行います。
バージョン
- python 3.9.0
- django 3.1.3
- django-graphql-jwt 0.3.1
- django-cors-headers 3.5.0
ライブラリのインストール
Djangoのプロジェクトが既に作成済みとして話を進めます。(名前はconfig)
$ pip install django-graphql-jwt==0.3.1 django-cors-headers==3.5.0
Settingファイルの修正
1.AuthenticationMiddleware
をMIDDLEWARE
に追加します。
MIDDLEWARE = [
# 追加
'django.contrib.auth.middleware.AuthenticationMiddleware',
]
2.JSONWebTokenMiddleware
をGRAPHENE
に追加します。
GRAPHENE = {
# configというプロジェクトを作成して、schemaというファイルを作成しています。
'SCHEMA': 'config.schema.schema',
'MIDDLEWARE': [
# 追加
'graphql_jwt.middleware.JSONWebTokenMiddleware',
],
}
3.JSONWebTokenBackend
をAUTHENTICATION_BACKENDS
に追加します。
AUTHENTICATION_BACKENDS = [
'graphql_jwt.backends.JSONWebTokenBackend',
'django.contrib.auth.backends.ModelBackend',
]
4.RefreshTokenConfig
とcorsheaders
をINSTALLED_APPS
に追加します。
RefreshTokenConfig
は、リフレッシュトークンをDBに保存するために、追加します。
追加後は、python manage.py migrate
を実行してください。
refresh_token_refreshtoken
テーブルが作成されます。
corsheaders
はCORSの設定のため、追加します。
INSTALLED_APPS = [
'corsheaders',
'graphql_jwt.refresh_token.apps.RefreshTokenConfig',
]
5.トークンの各種設定を追加します。
JWT_VERIFY_EXPIRATION
・・・有効期限を確認するように設定します。
JWT_LONG_RUNNING_REFRESH_TOKEN
・・・長期間有効なリフレッシュトークンを有効にします。
JWT_EXPIRATION_DELTA
・・・トークンの有効期限を5分に設定します。
JWT_REFRESH_EXPIRATION_DELTA
・・・リフレッシュトークンの有効期限を7日に設定します。
GRAPHQL_JWT = {
'JWT_VERIFY_EXPIRATION': True,
'JWT_LONG_RUNNING_REFRESH_TOKEN': True,
'JWT_EXPIRATION_DELTA': timedelta(minutes=5),
'JWT_REFRESH_EXPIRATION_DELTA': timedelta(days=7),
}
6.CORSの設定を追加します。
ローカルホストの3000番ポートからのアクセスを許可します。
CORS_ORIGIN_WHITELIST = [
"http://localhost:3000",
]
ルートスキーマの修正
プロジェクトフォルダ(config)に、schema.py
を作成してjwt認証のMutaion
を追加します。
import graphene
import graphql_jwt
class Mutation(graphene.ObjectType):
# トークン生成
token_auth = graphql_jwt.ObtainJSONWebToken.Field()
# トークン認証
verify_token = graphql_jwt.Verify.Field()
# トークンリフレッシュ
refresh_token = graphql_jwt.Refresh.Field()
# リフレッシュトークンの無効化
revoke_token = graphql_jwt.Revoke.Field()
# リフレッシュトークンを一度使用したら削除する設定を追加
@receiver(refresh_token_rotated)
def revoke_refresh_token(sender, request, refresh_token, **kwargs):
refresh_token.revoke(request)
schema = graphene.Schema(mutation=Mutation)
エンドポイントの作成
urls.py
を修正し、GraphQLのエンドポイントを作成します。
Django以外からアクセスしたときに、CSRF
のエラーが出るためcsrf_exempt
で機能を解除します。
from graphene_django.views import GraphQLView
from django.views.decorators.csrf import csrf_exempt
urlpatterns = [
path('graphql/', csrf_exempt(GraphQLView.as_view(graphiql=True)))
]
サンプルクエリ
設定は以上です。
参考に、各ユースケースのクエリをサンプルとして載せておきます。
クエリを実行したときに、payloadの取得やリフレッシュトークンのテーブルへの保存、無効化などがわかるかと思います。
- トークン生成
mutation TokenAuth($username: String!, $password: String!) {
tokenAuth(username: $username, password: $password) {
token
payload
refreshToken
refreshExpiresIn
}
}
- トークン認証
mutation VerifyToken($token: String!) {
verifyToken(token: $token) {
payload
}
}
- トークンリフレッシュ
mutation RefreshToken($refreshToken: String!) {
refreshToken(refreshToken: $refreshToken) {
token
payload
refreshToken
refreshExpiresIn
}
}
- リフレッシュトークンの無効化
mutation RevokeToken($refreshToken: String!) {
revokeToken(refreshToken: $refreshToken) {
revoked
}
}
最後に
今回はDjangoを利用してGraphQLのJWT認証を構築しました。
ライブラリを使うと簡単に構築できるので良いですね。
今回構築したJWT認証をフロントエンドのReactから使うことをこれから構築していく予定です。
構築できたらまた紹介できたらと思います。
参考サイト