24.05.06_TIL (Django 심화 : account 만들기 회원가입 JWT )
++ 장고 공식 문서는 항상 확인하기
https://docs.djangoproject.com/en/4.2/
++ 과제 API 를 정해주어서 수정하여 진행
필수 기능 - MVP(Minimum Viable Product)
- 회원가입
- Endpoint: /api/accounts
- Method: POST
- 조건: username, 비밀번호, 이메일, 이름, 닉네임, 생일 필수 입력하며 성별, 자기소개 생략 가능
- 검증: username과 이메일은 유일해야 하며, 이메일 중복 검증(선택 기능).
- 구현: 데이터 검증 후 저장.
- 로그인
- Endpoint: /api/accounts/login
- Method: POST
- 조건: 사용자명과 비밀번호 입력 필요.
- 검증: 사용자명과 비밀번호가 데이터베이스의 기록과 일치해야 함.
- 구현: 성공적인 로그인 시 토큰을 발급하고, 실패 시 적절한 에러 메시지를 반환.
- 프로필 조회
- Endpoint: /api/accounts/<str:username>
- Method: GET
- 조건: 로그인 상태 필요.
- 검증: 로그인 한 사용자만 프로필 조회 가능
- 구현: 로그인한 사용자의 정보를 JSON 형태로 반환.
1. account를 만들어보자.
- 데이터베이스를 초기화하고 비어있는 Custom User Model을 만들어 주세요.
- db.sqlite3를 지우고 각각의 migration 안의 파일을 지워주자.
- accounts 앱을 생성하고 User Model을 작성해 주세요.
python manage.py startapp accounts
- settings 에 AUTH_USER_MODEL 도 설정해야 합니다.
# Custom User Model
AUTH_USER_MODEL = 'accounts.User'
- accounts 의 models.py 에 추가해준다.
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
python manage.py makemigrations
python manage.py migrate
- /api//accounts/ 로 들어오면 accounts 앱의 urls로 연결해 주세요. - api_pjt 에 urls.py 에 추가해준다.
path('api/accounts/', include('accounts.urls')),
- accounts. 에 urls.py를 만들고 기본으로 적어준다.
from django.urls import path
from . import views
app_name = "accounts"
urlpatterns = []
- superuser 를 하나 생성해 주세요.
python manage.py createsuperuser
- DB를 초기화 했으니 seeding을 이용해서 article과 comment 데이터를 채워주세요.
python manage.py seed articles --number=30
python manage.py seed articles --number=20 --seeder "Comment.article_id" 1
2. JSON Web Token, JWT 구현하기
⭐ 쿠키 (Cookie)
- 웹 브라우저와 요청과 응답을 주고받을때 사용하는 데이터 조각
- 쿠키는 도메인에 제한적이며 유효기간이 정해져있음
- Auth 외에도 다양한 방식으로 활용 </aside>
⭐ 세션 (Session)
- stateless한 HTTP 특징을 보완하기 위한 방법
- 세션 DB를 이용해서 유저의 정보를 기억하며 Session ID라고 하는 랜덤한 Key를 쿠키에 담아서 Auth에 활용
- 쿠키를 사용해서 Session ID를 주고 받는 것 </aside>
⭐ 반드시 공식문서를 보고 적용할 수 있어야해요. https://django-rest-framework-simplejwt.readthedocs.io/en/latest/index.html
- 먼저 설치해주자.
pip install djangorestframework-simplejwt
pip freeze > reqirements.txt
- settings.py 에 추가해주자.
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework_simplejwt.authentication.JWTAuthentication",
],
}
- accounts. 에 urls.py에 추가해주자.
from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [
path("login/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
]
로그인을 하면 아래에 토큰이 만들어지는 것을 볼 수 있다.
- access token 이 만료되면 refresh token 으로 로그인 할 수 있게 해보자.
- login 에 있던 refresh 토큰을 복사하여 Refresh token 에 Json 방식으로 넣어주면 다시 새로운 access token 을 발급해주는 것을 볼 수 있다.
3. JWT 의 유효기간 설정하기
- settings.py 에 추가해준다.
from datetime import timedelta
...
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=1),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
"ROTATE_REFRESH_TOKENS": True,
"BLACKLIST_AFTER_ROTATION": True,
}
BLACKLIST_AFTER_ROTATION 을 쓰면 refresh 가 만료됐을 때 새로운 토큰을 발급받았다고 알려준다. 그 기능을 쓰기 위해서는 추가해주어야한다.
'rest_framework_simplejwt.token_blacklist',
그 다름 마이그레잇을 해준다. python manage.py migrate
똑같은 토큰을 쓰지 못하고 새로 발급된 토큰으로만 이제 쓸 수 있다.
4. 유저가 아니면 Article 기능 접근 제한
- articles 의 views.py 를 수정해준다.
from rest_framework.permissions import IsAuthenticated
...
class ArticleListAPIView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
def post(self, request):
serializer = ArticleSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
목록조회를 하는데도 이제 토큰이 없다면서 보여줄 수 없다고 나옴
이때 Refresh token 에서 발급받은 access 토큰을 목록조회의 Auth 에 넣어준다.
토큰이 만료된건지 어떤건지 유효할 수 없다고 나옴.
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=60),
토큰 만료기간을 60분으로 늘려주고 작업을 해보자. 그 전에는 1분이라서 만료된것임. 다시 엑세스 토큰을 발급받아서 해보면 아래처럼 잘 나오는 것을 볼 수 있다. (""는 떼고 복사해야한다.)
- view.py 에 permission_classes = [IsAuthenticated] 를 넣어서 다 토큰값이 없으면 볼 수 없도록 만들 수 있다.(로그인을 해야 댓글도 쓸수 있고 볼 수 있는 것으로 )
++ Token 유저정보 가져오기
- request.user