💯

WebAPIに認証機能を追加してみた

2024/05/29に公開

はじめに

今回は、以下の記事の続きになります。
https://zenn.dev/nihiru/articles/47bb11c1282ab5
上記の記事で、最後に触れましたが認証機能を追加してみました。
また、WebAPIを公開するうえで必要なテスト、公開用ドキュメントも作成しました。
それでは、本題に入ります。

認証機能の追加

Django REST frameworkを使用してトークン認証を実装し、セキュアなAPIを構築します。
1.パッケージのインストール
まず、必要なパッケージをインストールします。

pip install djangorestframework djangorestframework-authtoken

2. 設定ファイルの更新
'settings.py'に以下の設定を追加します。

settings.py
INSTALLED_APPS = [
    ...
    'rest_framework',
    'rest_framework.authtoken',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
}

3. マイグレーションの実行
トークン認証用のテーブルを作成します。

python manage.py migrate

4. トークン生成エンドポイントの追加
トークンを生成するためのビューとルーティングを追加します。

views.py
# books/views.py
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.response import Response

class CustomAuthToken(ObtainAuthToken):
    def post(self, request, *args, **kwargs):
        response = super(CustomAuthToken, self).post(request, *args, **kwargs)
        token = Token.objects.get(key=response.data['token'])
        return Response({'token': token.key})
urls.py
# books/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import BookViewSet, CustomAuthToken

router = DefaultRouter()
router.register(r'books', BookViewSet)

urlpatterns = [
    path('', include(router.urls)),
    path('api-token-auth/', CustomAuthToken.as_view()),
]

テストの追加

APIのユニットテストを追加して、機能が期待通りに動作することを確認します。
1.テストデータのセットアップ
テスト用のユーザーとトークンを作成し、テストクライアントに設定します。

test_views.py
# books/tests/test_views.py
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User
from books.models import Book

class BookAPITest(APITestCase):
    def setUp(self):
        # テスト用のユーザーを作成
        self.user = User.objects.create_user(username='testuser', password='testpassword')
        self.token = Token.objects.create(user=self.user)
        self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key)

        self.book = Book.objects.create(
            title="Test Book",
            author="Author",
            published_year=2023
        )
        self.url = reverse('book-list')

    def test_get_books(self):
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 1)
        self.assertEqual(response.data[0]['title'], "Test Book")

    def test_create_book(self):
        data = {
            "title": "New Book",
            "author": "New Author",
            "published_year": 2024
        }
        response = self.client.post(self.url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Book.objects.count(), 2)
        self.assertEqual(Book.objects.get(id=response.data['id']).title, "New Book")

2.テストの実行
テストを実行して、すべてのテストが成功することを確認します。

python manage.py test

ドキュメントの作成

Swaggerを使ってAPIのドキュメントを自動生成します。
1.drf-yasgのインストール
'drf-yasg'パッケージをインストールします。

pip install drf-yasg

2.ドキュメントの設定
'settings.py'に'drf_yasg'を追加します。

settings.py
INSTALLED_APPS = [
    ...
    'rest_framework',
    'rest_framework.authtoken',
    'drf_yasg',
]

3.ルーティングの設定
Swaggerのルートを追加します。

urls.py
# books/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import BookViewSet, CustomAuthToken
from rest_framework.schemas import get_schema_view
from drf_yasg.views import get_schema_view as swagger_get_schema_view
from drf_yasg import openapi

router = DefaultRouter()
router.register(r'books', BookViewSet)

schema_view = swagger_get_schema_view(
    openapi.Info(
        title="Book Management API",
        default_version='v1',
        description="API documentation for the Book Management application",
    ),
    public=True,
    permission_classes=(permissions.AllowAny,),
)

urlpatterns = [
    path('', include(router.urls)),
    path('api-token-auth/', CustomAuthToken.as_view()),
    path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
    path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]

まとめ

これで、認証機能の実装からテストの追加、ドキュメントの作成までの手順が完了しました。

Discussion