공식문서를 보면서 jwt와 user를 사용해보려고 한다.
여기서 소셜인증은 사용하지 않는다.
환경세팅
1. 패키지 설치
pip install djangorestframework pip install djangorestframework-simplejwt pip install django-allauth pip install dj-rest-auth
2. settings.py
# 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', 'rest_framework_simplejwt.token_blacklist', 'allauth', 'allauth.account' 'dj_rest_auth', 'dj_rest_auth.registration', # app 'bwh', 'accounts', ] SITE_ID = 1 AUTH_USER_MODEL = 'accounts.User' ... REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'dj_rest_auth.jwt_auth.JWTCookieAuthentication', ) } REST_USE_JWT = True
여기까지 설정을 dj-rest-auth문서 dj-rest-auth 공식문서 링크를 보고 설정할 수 있다.AUTH_USER_MODEL
은 accounts앱의 models.py에서 User를 사용하겠다고 설정한 부분이다.
다음으로 django-allauth 설정을 이어서 한다.
# settings.py ACCOUNT_USER_MODEL_USERNAME_FIELD = None ACCOUNT_EMAIL_REQUIRED = True ACCOUNT_USERNAME_REQUIRED = False ACCOUNT_AUTHENTICATION_METHOD = 'email'
django-allauth를 보고 작성했다.
작성한 명령어들의 설명은 다음과 같다.
ACCOUNT_USER_MODEL_USERNAME_FIELD
: 커스텀 사용자 모델을 사용하는 경우 아이디 필드의 이름이 username이 아닌 다른 이름일 경우 지정한다.
만약 None으로 지정할 경우 allauth에서 username과 관련된 모든 기능을 사용하지 않는다.
이 경우 ACCOUNT_USERNAME_REQUIRED 값 또한 반드시 False로 지정해야 한다.ACCOUNT_EMAIL_REQUIRED
: 회원가입할 때 이메일 주소 입력 필수 여부이다. 디폴트 값은 False이다.ACCOUNT_USERNAME_REQUIRED
: 회원 가입할 때 username 입력 필수 여부이다. 디폴트 값은 True이므로 반드시 ACCOUNT_AUTHENTICATION_METHOD를 통해 이메일로 로그인으로 설정하더라도 username을 입력해야 가입된다.ACCOUNT_AUTHENTICATION_METHOD
: 로그인 인증 방법으로 username, email, username_email을 지정할 수 있다. email로 설정할 때는 ACCOUNT_EMAIL_REQUIRED = True 옵션을 같이 설정해야 한다.
# settings.py from datetime import timedelta SIMPLE_JWT = { 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5), 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), 'ROTATE_REFRESH_TOKENS': False, 'BLACKLIST_AFTER_ROTATION': False, 'UPDATE_LAST_LOGIN': False, 'ALGORITHM': 'HS256', 'SIGNING_KEY': SECRET_KEY, 'VERIFYING_KEY': None, 'AUDIENCE': None, 'ISSUER': None, 'JWK_URL': None, 'LEEWAY': 0, 'AUTH_HEADER_TYPES': ('Bearer',), 'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION', 'USER_ID_FIELD': 'id', 'USER_ID_CLAIM': 'user_id', 'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule', 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), 'TOKEN_TYPE_CLAIM': 'token_type', 'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser', 'JTI_CLAIM': 'jti', 'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp', 'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5), 'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1), }
simple-jwt를 보고 작성했다.
5번 라인과, 6번 라인을 통해 토큰의 유효기간을 정할 수 있다.
3. urls.py
# urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('bwh/', include('bwh.urls')), path('accounts/', include('accounts.urls')), ]
app Setting
1. app/models.py
# accounts/models.py from django.db import models from django.contrib.auth.models import AbstractBaseUser class User(AbstractBaseUser): email = models.EmailField('EMAIL', max_length=100, null=False, blank=False, unique=True) nickname = models.CharField('NICKNAME', max_length=100, null=False, blank=False) profile_image = models.ImageField('PROFILE_IMG', upload_to='user/%Y/%m', blank=True, null=True) USERNAME_FIELD = 'email' def __str__(self): return self.nickname class Meta: db_table = 'accounts'
회원가입에서는 AbstractBaseUser를 사용한다.
AbstractBaseUser는 간단하게 설명하면 username 컬럼을 사용 안할 때 상속하여 사용한다.
AbstractUser는 username 컬럼을 사용할 때 상속한다.
2. app/serializers.py
# accounts/serializers.py from rest_framework import serializers from dj_rest_auth.registration.serializers import RegisterSerializer from rest_framework.validators import UniqueValidator from .models import User class CustomRegisterSerializer(RegisterSerializer): ''' 회원가입 Custom ''' username = None nickname = serializers.CharField(required=True, validators=[UniqueValidator(queryset=User.objects.all(), message=("Name already exists"))]) profile_image = serializers.ImageField(use_url=True) def get_cleaned_data(self): data = super().get_cleaned_data() data['profile_image'] = self.validated_data.get('profile_image', '') data['username'] = self.validated_data.get('username') return data
serializers에서 사용하는 field에 대한 설명은 drf 문서에 설명이 잘 나와 있다.
RegisterSerializer는 기본적으로 username, email, password만 받아준다. models.py에 추가한 nickname과 profile_image도 넣어주기 위해 get_cleaned_data를 오버라이딩 해준다.
그리고 custom을 했다면 settings.py에 serializers를 재정의 해줘야한다.
# settings.py REST_AUTH_REGISTER_SERIALIZERS = { 'REGISTER_SERIALIZER': 'accounts.serializers.CustomRegisterSerializer', }
3. app/adapter.py
RegisterSerializer를 상속받아 커스텀하였을 때, 추가한 필드들은 입력값이 저장이 안된다.
이 문제를 해결하기 위해서는 adapter도 수정해야 한다.
참고 : 참고 블로그
# accounts/adapter.py from allauth.account.adapter import DefaultAccountAdapter from allauth.account.utils import user_field class CustomAccountAdapter(DefaultAccountAdapter): def save_user(self, request, user, form, commit=True): data = form.cleaned_data user = super().save_user(request, user, form, False) # 추가 필드 nickname = data.get('nickname') profile_image = data.get('profile_image') if nickname: user.nickname = nickname if profile_image: user.profile_image = profile_image user.save() return user
allauth.account.adapter.DefaultAccountAdapter에서 save_user를 가져와서 오버라이딩을 해줬다.
4. app/urls.py
# accounts/urls.py from django.urls import path, include urlpatterns = [ path('', include('dj_rest_auth.urls')), path('signup/', include('dj_rest_auth.registration.urls')), ]
결과
이제 로그인을 하면 토큰과 user의 pk, email이 나타난다.

'DevOps > Django' 카테고리의 다른 글
[Django] django extensions shell_plus 사용하기 (0) | 2022.05.16 |
---|---|
[Django] 장고 모델(ORM) (0) | 2022.05.11 |
[DRF] pagination custom (0) | 2022.03.24 |
[DRF] 직렬화, 역직렬화 (0) | 2022.03.23 |
[Django] 참고사이트 (0) | 2022.03.22 |