0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Djangoのfixtureで登録したユーザーでテストClientのログイン認証に一瞬だけ手間取った話

Last updated at Posted at 2022-11-05

開発環境

  • Python 3.9
  • Django==3.2.12
  • djangorestframework==3.13.1

困ったこと。

DjangoでModelSetViewを使ったAPIの開発で、
ログイン認証の必要なAPIのテストをしているとき。

tests.py
class TestAuthApi(TestCase):
    '''認証APIのテスト'''

    AUTH_URL = '/api-token-auth/' # 認証用URL
    fixtures = ['fixtures/test/test_data.json']
    
    def test_token(self):
        '''POSTメソッドのテスト'''
        client = Client()
        # トークン取得
        token_response = client.post(
            self.AUTH_URL,
            data={
                "username": "testuser",
                "password": "password",
                "email": "testuser@test.com",
            },
            content_type='application/json',
        )
        # トークン認証のチェック
        self.assertEqual(token_response.status_code, 200)
        self.assertTrue('token' in token_response.json())

python manage.py testで実行すると、

AssertionError: 401 != 200

がraiseされた。
認証できていないということですね。

ちゃんと、ユーザー名も、パスワードも、メールアドレスも間違っていないことを確認しているので、なにが間違っているのだろう?
(python manage.py createsuperuserで作ったユーザーでは、Webブラウザ、API共に認証できているので、User周りの設定が間違っていることはないだろう。)

関連するファイルの関連する箇所

models.py
from django.contrib.auth.models import AbstractUser
()

class User(AbstractUser):
    pass

()
serializers.py
from rest_framework import serializers
from django.contrib.auth import get_user_model
()

class UserSerializer(serializers.ModelSerializer):
    """ユーザーシリアライザー"""
    class Meta:
        model = get_user_model()
        fields = ('id', 'username', 'email')
()
urls.py
from rest_framework.authtoken import views as auth_views
()

urlpatterns = [
    ()
    # トークン認証用エンドポイント
    url(r'^api-token-auth/', auth_views.obtain_auth_token),
]
settings.py
()

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework.authtoken',
    ()
]

()

AUTH_USER_MODEL = 'apiv1.User'

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES':[
        'rest_framework.authentication.TokenAuthentication', # トークン認証
        'rest_framework.authentication.SessionAuthentication', # セッション認証
    ]
}

()
test_data.json
[
    {
        "model": "アプリ名.user",
        "pk": 1,
        "fields": {
            "username": "testuser",
            "password": "password",
            "email": "testuser@test.com",
            (略)
        }
    },
]

解決策

「Webブラウザ、APIでは認証できているのに、テストClientでは認証できない。」
→ということは、テスト用データが間違っているのでは?

よくよく考えたら、テスト用データにパスワードの平文を書いたけど、DBに平文が保存されるはずないよね、、、

ということで調べると、Djangoではmake_password関数を使って、パスワードをハッシュ化して保存している。

なので、fixtureのデータをパスワードのハッシュ値にすればよい。
ということで、ハッシュ値の取得を行う。

# python manage.py shell
>>> from django.contrib.auth.hashers import make_password
>>> make_password('password')
'pbkdf2_sha256$260000$O2CJugvRp7L8GMfcLfv8eZ$X8Mf8PPmtf37Emg2nD42bJ/m3PQF+jYVpgKEifiDbHo='

これを、fixtureに入れて、

test_data.json
[
    {
        "model": "アプリ名.user",
        "pk": 1,
        "fields": {
            "username": "testuser",
            "password": "pbkdf2_sha256$260000$O2CJugvRp7L8GMfcLfv8eZ$X8Mf8PPmtf37Emg2nD42bJ/m3PQF+jYVpgKEifiDbHo=",
            "email": "testuser@test.com",
            (略)
        }
    },
]

として、再度python manage.py testを実行すると、

OK!!!

初歩的なミスでしたが、こういうのを地道に解決していく過程でフレームワークへの理解が深まったりしますよね。
(「テスト用のユーザー登録からやればいいじゃん」というよのは内緒。)

参考

https://medium.com/p/64a4b38904ff#9c63
(ちょっと古いけど。)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?