From 387542c791c0366c5e25d6006057205802bce54c Mon Sep 17 00:00:00 2001 From: Jaehee Date: Sun, 4 Aug 2024 10:09:03 +0900 Subject: [PATCH 1/6] feat: Create views for 42OAuth Login --- backend/django/requirements.txt | 3 + backend/django/templates/django/login.html | 16 +++++ backend/django/transcendence/settings.py | 4 +- backend/django/users/urls.py | 10 +++ backend/django/users/views.py | 76 ++++++++++++++++++++++ 5 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 backend/django/templates/django/login.html diff --git a/backend/django/requirements.txt b/backend/django/requirements.txt index 683f125..edd5834 100644 --- a/backend/django/requirements.txt +++ b/backend/django/requirements.txt @@ -13,3 +13,6 @@ setuptools==71.1.0 sqlparse==0.5.1 typing_extensions==4.12.2 uritemplate==4.1.1 + +# feature01-42OAuth_Login 에서 추가됨 +requests==2.31.0 \ No newline at end of file diff --git a/backend/django/templates/django/login.html b/backend/django/templates/django/login.html new file mode 100644 index 0000000..c67dbdd --- /dev/null +++ b/backend/django/templates/django/login.html @@ -0,0 +1,16 @@ + + + + + 42 OAuth 로그인 + + + + + + + \ No newline at end of file diff --git a/backend/django/transcendence/settings.py b/backend/django/transcendence/settings.py index 6ac1166..31e0cd7 100644 --- a/backend/django/transcendence/settings.py +++ b/backend/django/transcendence/settings.py @@ -43,6 +43,7 @@ 'drf_yasg', 'ansanking', "users", + "django", ] MIDDLEWARE = [ @@ -70,7 +71,8 @@ TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], + # feature01-42OAuth_Login 에서 추가됨 원래 [] 로 비어있었음 + 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ diff --git a/backend/django/users/urls.py b/backend/django/users/urls.py index 2da8a41..bcfd2a6 100644 --- a/backend/django/users/urls.py +++ b/backend/django/users/urls.py @@ -3,10 +3,20 @@ get_user, get_user_list, create_user, + + # feature01-42OAuth_Login 에서 추가됨 + login, + callback, + login_view, ) urlpatterns = [ path('user/get/', get_user_list), path('user/get//', get_user), path('user/create//', create_user), + + # feature01-42OAuth_Login 에서 추가됨 + path('login/', login), + path('callback/', callback), + path('login/view/', login_view), ] diff --git a/backend/django/users/views.py b/backend/django/users/views.py index 6343443..aa35e9e 100644 --- a/backend/django/users/views.py +++ b/backend/django/users/views.py @@ -5,6 +5,11 @@ from .models import User, Friend, Game, Tournament from .serializers import UserSerializer, FriendSerializer, GameSerializer, TournamentSerializer +# feature01-42OAuth_Login 에서 추가됨 +import requests +from django.shortcuts import redirect +from django.shortcuts import render +from django.conf import settings @api_view(["GET"]) def get_user(request, nickname): @@ -32,3 +37,74 @@ def create_user(request, nickname): user.save() serializer = UserSerializer(user) return JsonResponse(serializer.data, status=status.HTTP_201_CREATED) + + +# feature01-42OAuth_Login 에서 추가됨 +def login_view(request): + return render(request, 'django/login.html') + + +def login(request): + oauth_url = "https://api.intra.42.fr/oauth/authorize" + client_id = "u-s4t2ud-9bd5c0e972b48a45c2d1d443e8f8a46e8224352693fd09c443212d15919f7521" # 실제 클라이언트 ID로 변경 + redirect_uri = "http://localhost:8000/api/callback" + state = "random_state_string" # CSRF 방지용 랜덤 문자열 + + return redirect(f"{oauth_url}?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&state={state}") + + +def callback(request): + code = request.GET.get('code') + if not code: + return redirect('/') # 코드가 없으면 리디렉션 + + token_url = "https://api.intra.42.fr/oauth/token" + client_id = "u-s4t2ud-9bd5c0e972b48a45c2d1d443e8f8a46e8224352693fd09c443212d15919f7521" # 실제 클라이언트 ID로 변경 + client_secret = "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" # 실제 클라이언트 시크릿으로 변경 + redirect_uri = "http://localhost:8000/api/callback" + + data = { + 'grant_type': 'authorization_code', + 'code': code, + 'client_id': client_id, + 'client_secret': client_secret, + 'redirect_uri': redirect_uri, + } + + response = requests.post(token_url, data=data) + if response.status_code != 200: + return redirect('/') # 오류 발생 시 리디렉션 + + token_data = response.json() + access_token = token_data.get('access_token') + + # Access Token을 사용하여 사용자 정보 가져오기 + user_info = requests.get("https://api.intra.42.fr/v2/me", headers={"Authorization": f"Bearer {access_token}"}) + if user_info.status_code != 200: + return redirect('/') # 사용자 정보 가져오기 실패 시 리디렉션 + + user_data = user_info.json() + + # 사용자 정보 처리 (예: DB 저장) + nickname = user_data.get('login') # 42 API에서 사용자 로그인 이름 + img_url = user_data.get('image', {}).get('link') # 42 API에서 사용자 이미지 URL + is_2FA = user_data.get('is_2fa', False) # 2FA 여부 + is_online = False # 기본값으로 설정 (온라인 상태는 API에서 제공하지 않음) + + # 사용자 정보 저장 또는 업데이트 + user, created = User.objects.update_or_create( + nickname=nickname, + defaults={ + 'img_url': img_url, + 'is_2FA': is_2FA, + 'is_online': is_online + } + ) + + # 생성된 경우, 추가 로직 (예: 환영 메시지 등) + if created: + print(f"새 사용자 생성: {nickname}") + else: + print(f"기존 사용자 업데이트: {nickname}") + + return redirect('/') # 로그인 후 리디렉션 \ No newline at end of file From c8491573336837f5728eadc5e499822d328a2e65 Mon Sep 17 00:00:00 2001 From: seungwonme Date: Sun, 4 Aug 2024 16:52:38 +0900 Subject: [PATCH 2/6] refactor: Change the structure of the project --- backend/Dockerfile | 2 +- backend/django/ansanking/urls.py | 6 --- backend/django/ansanking/views.py | 7 ---- backend/django/templates/django/login.html | 16 -------- backend/{django => }/docker-run-server.sh | 0 .../{django/ansanking => login}/__init__.py | 0 backend/{django/ansanking => login}/admin.py | 0 backend/{django/ansanking => login}/apps.py | 4 +- .../migrations/__init__.py | 0 backend/{django/ansanking => login}/models.py | 0 backend/{django/ansanking => login}/tests.py | 0 backend/{django/users => login}/views.py | 40 ++----------------- backend/{django => }/manage.py | 0 backend/{django => }/requirements.txt | 4 +- backend/{django => }/run-server.sh | 9 +---- .../{django => }/transcendence/__init__.py | 0 backend/{django => }/transcendence/asgi.py | 0 .../{django => }/transcendence/settings.py | 5 +-- backend/{django => }/transcendence/urls.py | 9 +---- backend/{django => }/transcendence/wsgi.py | 0 backend/{django => }/users/__init__.py | 0 backend/{django => }/users/admin.py | 0 backend/{django => }/users/apps.py | 0 .../users/migrations/0001_initial.py | 0 .../{django => }/users/migrations/__init__.py | 0 backend/{django => }/users/models.py | 0 backend/{django => }/users/serializers.py | 0 backend/{django => }/users/tests.py | 0 backend/{django => }/users/urls.py | 0 backend/users/views.py | 34 ++++++++++++++++ frontend/{vite => }/.gitignore | 0 frontend/Dockerfile | 4 +- frontend/{vite => }/index.html | 0 frontend/{vite => }/package-lock.json | 0 frontend/{vite => }/package.json | 0 frontend/{vite => }/src/app.js | 0 frontend/{vite => }/src/components/AddCal.js | 0 frontend/{vite => }/src/components/Default.js | 0 .../{vite => }/src/components/Friends-Info.js | 0 frontend/{vite => }/src/components/Friends.js | 0 .../{vite => }/src/components/Home-Login.js | 0 frontend/{vite => }/src/components/Home.js | 0 frontend/{vite => }/src/components/List.js | 0 .../{vite => }/src/components/Main-Menu.js | 0 frontend/{vite => }/src/components/Main.js | 0 frontend/{vite => }/src/core/Component.js | 0 frontend/{vite => }/src/core/observer.js | 0 frontend/{vite => }/src/core/router.js | 0 frontend/{vite => }/style.css | 0 frontend/{vite => }/vite.config.js | 0 run_backend.sh | 2 +- run_frontend.sh | 2 +- 52 files changed, 50 insertions(+), 94 deletions(-) delete mode 100644 backend/django/ansanking/urls.py delete mode 100644 backend/django/ansanking/views.py delete mode 100644 backend/django/templates/django/login.html rename backend/{django => }/docker-run-server.sh (100%) rename backend/{django/ansanking => login}/__init__.py (100%) rename backend/{django/ansanking => login}/admin.py (100%) rename backend/{django/ansanking => login}/apps.py (62%) rename backend/{django/ansanking => login}/migrations/__init__.py (100%) rename backend/{django/ansanking => login}/models.py (100%) rename backend/{django/ansanking => login}/tests.py (100%) rename backend/{django/users => login}/views.py (68%) rename backend/{django => }/manage.py (100%) rename backend/{django => }/requirements.txt (82%) rename backend/{django => }/run-server.sh (91%) rename backend/{django => }/transcendence/__init__.py (100%) rename backend/{django => }/transcendence/asgi.py (100%) rename backend/{django => }/transcendence/settings.py (98%) rename backend/{django => }/transcendence/urls.py (87%) rename backend/{django => }/transcendence/wsgi.py (100%) rename backend/{django => }/users/__init__.py (100%) rename backend/{django => }/users/admin.py (100%) rename backend/{django => }/users/apps.py (100%) rename backend/{django => }/users/migrations/0001_initial.py (100%) rename backend/{django => }/users/migrations/__init__.py (100%) rename backend/{django => }/users/models.py (100%) rename backend/{django => }/users/serializers.py (100%) rename backend/{django => }/users/tests.py (100%) rename backend/{django => }/users/urls.py (100%) create mode 100644 backend/users/views.py rename frontend/{vite => }/.gitignore (100%) rename frontend/{vite => }/index.html (100%) rename frontend/{vite => }/package-lock.json (100%) rename frontend/{vite => }/package.json (100%) rename frontend/{vite => }/src/app.js (100%) rename frontend/{vite => }/src/components/AddCal.js (100%) rename frontend/{vite => }/src/components/Default.js (100%) rename frontend/{vite => }/src/components/Friends-Info.js (100%) rename frontend/{vite => }/src/components/Friends.js (100%) rename frontend/{vite => }/src/components/Home-Login.js (100%) rename frontend/{vite => }/src/components/Home.js (100%) rename frontend/{vite => }/src/components/List.js (100%) rename frontend/{vite => }/src/components/Main-Menu.js (100%) rename frontend/{vite => }/src/components/Main.js (100%) rename frontend/{vite => }/src/core/Component.js (100%) rename frontend/{vite => }/src/core/observer.js (100%) rename frontend/{vite => }/src/core/router.js (100%) rename frontend/{vite => }/style.css (100%) rename frontend/{vite => }/vite.config.js (100%) diff --git a/backend/Dockerfile b/backend/Dockerfile index fce60ef..d42c73a 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -13,7 +13,7 @@ RUN apt-get update && apt-get install -y \ WORKDIR /app -COPY ./django/ . +COPY . . RUN chmod -R 755 /app CMD ["sh", "docker-run-server.sh"] diff --git a/backend/django/ansanking/urls.py b/backend/django/ansanking/urls.py deleted file mode 100644 index 66c01e7..0000000 --- a/backend/django/ansanking/urls.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.urls import path -from .views import ansan_king - -urlpatterns = [ - path('ansan-king/', ansan_king, name='ansan-king'), -] diff --git a/backend/django/ansanking/views.py b/backend/django/ansanking/views.py deleted file mode 100644 index f613eed..0000000 --- a/backend/django/ansanking/views.py +++ /dev/null @@ -1,7 +0,0 @@ -from rest_framework.decorators import api_view -from rest_framework.response import Response - -@api_view(['GET']) -def ansan_king(request): - data = {"message": "AnsanKing!!"} - return Response(data) diff --git a/backend/django/templates/django/login.html b/backend/django/templates/django/login.html deleted file mode 100644 index c67dbdd..0000000 --- a/backend/django/templates/django/login.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - 42 OAuth 로그인 - - - - - - - \ No newline at end of file diff --git a/backend/django/docker-run-server.sh b/backend/docker-run-server.sh similarity index 100% rename from backend/django/docker-run-server.sh rename to backend/docker-run-server.sh diff --git a/backend/django/ansanking/__init__.py b/backend/login/__init__.py similarity index 100% rename from backend/django/ansanking/__init__.py rename to backend/login/__init__.py diff --git a/backend/django/ansanking/admin.py b/backend/login/admin.py similarity index 100% rename from backend/django/ansanking/admin.py rename to backend/login/admin.py diff --git a/backend/django/ansanking/apps.py b/backend/login/apps.py similarity index 62% rename from backend/django/ansanking/apps.py rename to backend/login/apps.py index 0a5a67c..ebd58e7 100644 --- a/backend/django/ansanking/apps.py +++ b/backend/login/apps.py @@ -1,6 +1,6 @@ from django.apps import AppConfig -class AnsankingConfig(AppConfig): +class LoginConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'ansanking' + name = 'login' diff --git a/backend/django/ansanking/migrations/__init__.py b/backend/login/migrations/__init__.py similarity index 100% rename from backend/django/ansanking/migrations/__init__.py rename to backend/login/migrations/__init__.py diff --git a/backend/django/ansanking/models.py b/backend/login/models.py similarity index 100% rename from backend/django/ansanking/models.py rename to backend/login/models.py diff --git a/backend/django/ansanking/tests.py b/backend/login/tests.py similarity index 100% rename from backend/django/ansanking/tests.py rename to backend/login/tests.py diff --git a/backend/django/users/views.py b/backend/login/views.py similarity index 68% rename from backend/django/users/views.py rename to backend/login/views.py index aa35e9e..0ec9f0e 100644 --- a/backend/django/users/views.py +++ b/backend/login/views.py @@ -1,43 +1,9 @@ -from django.shortcuts import get_object_or_404 -from django.http import JsonResponse -from rest_framework.decorators import api_view -from rest_framework import status -from .models import User, Friend, Game, Tournament -from .serializers import UserSerializer, FriendSerializer, GameSerializer, TournamentSerializer - -# feature01-42OAuth_Login 에서 추가됨 +from django.shortcuts import render import requests from django.shortcuts import redirect from django.shortcuts import render from django.conf import settings - -@api_view(["GET"]) -def get_user(request, nickname): - try: - user = get_object_or_404(User, nickname=nickname) - except User.DoesNotExist: - return JsonResponse({"detail": "Not found."}, status=status.HTTP_404_NOT_FOUND) - - serializer = UserSerializer(user) - return JsonResponse(serializer.data) - - -@api_view(["GET"]) -def get_user_list(request): - users = User.objects.all() - serializer = UserSerializer(users, many=True) - return JsonResponse(serializer.data, safe=False) - - -@api_view(["POST"]) -def create_user(request, nickname): - if User.objects.filter(nickname=nickname).exists(): - return JsonResponse({"detail": "User already exists."}, status=status.HTTP_400_BAD_REQUEST) - user = User(nickname=nickname) - user.save() - serializer = UserSerializer(user) - return JsonResponse(serializer.data, status=status.HTTP_201_CREATED) - +from users.models import User # feature01-42OAuth_Login 에서 추가됨 def login_view(request): @@ -107,4 +73,4 @@ def callback(request): else: print(f"기존 사용자 업데이트: {nickname}") - return redirect('/') # 로그인 후 리디렉션 \ No newline at end of file + return redirect('/') # 로그인 후 리디렉션 diff --git a/backend/django/manage.py b/backend/manage.py similarity index 100% rename from backend/django/manage.py rename to backend/manage.py diff --git a/backend/django/requirements.txt b/backend/requirements.txt similarity index 82% rename from backend/django/requirements.txt rename to backend/requirements.txt index edd5834..7aaf315 100644 --- a/backend/django/requirements.txt +++ b/backend/requirements.txt @@ -13,6 +13,4 @@ setuptools==71.1.0 sqlparse==0.5.1 typing_extensions==4.12.2 uritemplate==4.1.1 - -# feature01-42OAuth_Login 에서 추가됨 -requests==2.31.0 \ No newline at end of file +requests==2.31.0 diff --git a/backend/django/run-server.sh b/backend/run-server.sh similarity index 91% rename from backend/django/run-server.sh rename to backend/run-server.sh index 0bffca7..1a76f2a 100755 --- a/backend/django/run-server.sh +++ b/backend/run-server.sh @@ -6,13 +6,9 @@ DOT_ENV_FILE=".env" # 스크립트 파일의 디렉토리로 이동 cd "$(dirname "$0")" -if [ -f "$DOT_ENV_FILE" ]; then - echo "$DOT_ENV_FILE already exists." -else - cp ../../$DOT_ENV_FILE . +cp ../$DOT_ENV_FILE . echo "Copied $DOT_ENV_FILE." sed -i '' 's/^DB_HOST=.*$/DB_HOST=localhost/' .env -fi # TEST: .env 파일의 변수들을 환경 변수로 설정 (슈퍼 유저를 생성하기 위해 필요) if [ -f "$DOT_ENV_FILE" ]; then @@ -20,10 +16,9 @@ if [ -f "$DOT_ENV_FILE" ]; then echo "Exported .env variables to environment." else echo ".env file not found." + exit 1 fi -rm $DOT_ENV_FILE - if [ ! -d "$ENV_DIR" ]; then python3 -m venv $ENV_DIR echo "Virtual environment created at $ENV_DIR." diff --git a/backend/django/transcendence/__init__.py b/backend/transcendence/__init__.py similarity index 100% rename from backend/django/transcendence/__init__.py rename to backend/transcendence/__init__.py diff --git a/backend/django/transcendence/asgi.py b/backend/transcendence/asgi.py similarity index 100% rename from backend/django/transcendence/asgi.py rename to backend/transcendence/asgi.py diff --git a/backend/django/transcendence/settings.py b/backend/transcendence/settings.py similarity index 98% rename from backend/django/transcendence/settings.py rename to backend/transcendence/settings.py index 31e0cd7..ce44b55 100644 --- a/backend/django/transcendence/settings.py +++ b/backend/transcendence/settings.py @@ -41,9 +41,8 @@ 'rest_framework', "corsheaders", 'drf_yasg', - 'ansanking', - "users", - "django", + "users.apps.UsersConfig", + "login.apps.LoginConfig", ] MIDDLEWARE = [ diff --git a/backend/django/transcendence/urls.py b/backend/transcendence/urls.py similarity index 87% rename from backend/django/transcendence/urls.py rename to backend/transcendence/urls.py index f262c11..6abc1ec 100644 --- a/backend/django/transcendence/urls.py +++ b/backend/transcendence/urls.py @@ -20,12 +20,6 @@ from drf_yasg.views import get_schema_view from drf_yasg import openapi from django.urls import include -from django.http import HttpResponse -from users import views - -# 홈 페이지 뷰 함수 추가 -def home(request): - return HttpResponse("Hello, world!") # Swagger 설정 schema_view = get_schema_view( @@ -44,10 +38,9 @@ def home(request): # URL 패턴 설정 urlpatterns = [ path('admin/', admin.site.urls), - path('', home, name='home'), - path('api/', include('ansanking.urls')), re_path(r'^swagger(?P\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'), 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'), path('api/', include('users.urls')), + path('api/', include('login.urls')), ] diff --git a/backend/django/transcendence/wsgi.py b/backend/transcendence/wsgi.py similarity index 100% rename from backend/django/transcendence/wsgi.py rename to backend/transcendence/wsgi.py diff --git a/backend/django/users/__init__.py b/backend/users/__init__.py similarity index 100% rename from backend/django/users/__init__.py rename to backend/users/__init__.py diff --git a/backend/django/users/admin.py b/backend/users/admin.py similarity index 100% rename from backend/django/users/admin.py rename to backend/users/admin.py diff --git a/backend/django/users/apps.py b/backend/users/apps.py similarity index 100% rename from backend/django/users/apps.py rename to backend/users/apps.py diff --git a/backend/django/users/migrations/0001_initial.py b/backend/users/migrations/0001_initial.py similarity index 100% rename from backend/django/users/migrations/0001_initial.py rename to backend/users/migrations/0001_initial.py diff --git a/backend/django/users/migrations/__init__.py b/backend/users/migrations/__init__.py similarity index 100% rename from backend/django/users/migrations/__init__.py rename to backend/users/migrations/__init__.py diff --git a/backend/django/users/models.py b/backend/users/models.py similarity index 100% rename from backend/django/users/models.py rename to backend/users/models.py diff --git a/backend/django/users/serializers.py b/backend/users/serializers.py similarity index 100% rename from backend/django/users/serializers.py rename to backend/users/serializers.py diff --git a/backend/django/users/tests.py b/backend/users/tests.py similarity index 100% rename from backend/django/users/tests.py rename to backend/users/tests.py diff --git a/backend/django/users/urls.py b/backend/users/urls.py similarity index 100% rename from backend/django/users/urls.py rename to backend/users/urls.py diff --git a/backend/users/views.py b/backend/users/views.py new file mode 100644 index 0000000..6343443 --- /dev/null +++ b/backend/users/views.py @@ -0,0 +1,34 @@ +from django.shortcuts import get_object_or_404 +from django.http import JsonResponse +from rest_framework.decorators import api_view +from rest_framework import status +from .models import User, Friend, Game, Tournament +from .serializers import UserSerializer, FriendSerializer, GameSerializer, TournamentSerializer + + +@api_view(["GET"]) +def get_user(request, nickname): + try: + user = get_object_or_404(User, nickname=nickname) + except User.DoesNotExist: + return JsonResponse({"detail": "Not found."}, status=status.HTTP_404_NOT_FOUND) + + serializer = UserSerializer(user) + return JsonResponse(serializer.data) + + +@api_view(["GET"]) +def get_user_list(request): + users = User.objects.all() + serializer = UserSerializer(users, many=True) + return JsonResponse(serializer.data, safe=False) + + +@api_view(["POST"]) +def create_user(request, nickname): + if User.objects.filter(nickname=nickname).exists(): + return JsonResponse({"detail": "User already exists."}, status=status.HTTP_400_BAD_REQUEST) + user = User(nickname=nickname) + user.save() + serializer = UserSerializer(user) + return JsonResponse(serializer.data, status=status.HTTP_201_CREATED) diff --git a/frontend/vite/.gitignore b/frontend/.gitignore similarity index 100% rename from frontend/vite/.gitignore rename to frontend/.gitignore diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 491657f..0470861 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -4,7 +4,7 @@ FROM node:22.5-alpine3.19 WORKDIR /app # 3. package.json 및 package-lock.json을 복사합니다. -COPY vite/package*.json ./ +COPY package*.json ./ # 4. 의존성을 설치합니다. RUN npm install && \ @@ -12,7 +12,7 @@ RUN npm install && \ apk add --no-cache curl # 5. 나머지 애플리케이션 소스를 복사합니다. -COPY vite/ . +COPY . . # 6. Vite 서버를 실행합니다. CMD ["npm", "run", "dev"] diff --git a/frontend/vite/index.html b/frontend/index.html similarity index 100% rename from frontend/vite/index.html rename to frontend/index.html diff --git a/frontend/vite/package-lock.json b/frontend/package-lock.json similarity index 100% rename from frontend/vite/package-lock.json rename to frontend/package-lock.json diff --git a/frontend/vite/package.json b/frontend/package.json similarity index 100% rename from frontend/vite/package.json rename to frontend/package.json diff --git a/frontend/vite/src/app.js b/frontend/src/app.js similarity index 100% rename from frontend/vite/src/app.js rename to frontend/src/app.js diff --git a/frontend/vite/src/components/AddCal.js b/frontend/src/components/AddCal.js similarity index 100% rename from frontend/vite/src/components/AddCal.js rename to frontend/src/components/AddCal.js diff --git a/frontend/vite/src/components/Default.js b/frontend/src/components/Default.js similarity index 100% rename from frontend/vite/src/components/Default.js rename to frontend/src/components/Default.js diff --git a/frontend/vite/src/components/Friends-Info.js b/frontend/src/components/Friends-Info.js similarity index 100% rename from frontend/vite/src/components/Friends-Info.js rename to frontend/src/components/Friends-Info.js diff --git a/frontend/vite/src/components/Friends.js b/frontend/src/components/Friends.js similarity index 100% rename from frontend/vite/src/components/Friends.js rename to frontend/src/components/Friends.js diff --git a/frontend/vite/src/components/Home-Login.js b/frontend/src/components/Home-Login.js similarity index 100% rename from frontend/vite/src/components/Home-Login.js rename to frontend/src/components/Home-Login.js diff --git a/frontend/vite/src/components/Home.js b/frontend/src/components/Home.js similarity index 100% rename from frontend/vite/src/components/Home.js rename to frontend/src/components/Home.js diff --git a/frontend/vite/src/components/List.js b/frontend/src/components/List.js similarity index 100% rename from frontend/vite/src/components/List.js rename to frontend/src/components/List.js diff --git a/frontend/vite/src/components/Main-Menu.js b/frontend/src/components/Main-Menu.js similarity index 100% rename from frontend/vite/src/components/Main-Menu.js rename to frontend/src/components/Main-Menu.js diff --git a/frontend/vite/src/components/Main.js b/frontend/src/components/Main.js similarity index 100% rename from frontend/vite/src/components/Main.js rename to frontend/src/components/Main.js diff --git a/frontend/vite/src/core/Component.js b/frontend/src/core/Component.js similarity index 100% rename from frontend/vite/src/core/Component.js rename to frontend/src/core/Component.js diff --git a/frontend/vite/src/core/observer.js b/frontend/src/core/observer.js similarity index 100% rename from frontend/vite/src/core/observer.js rename to frontend/src/core/observer.js diff --git a/frontend/vite/src/core/router.js b/frontend/src/core/router.js similarity index 100% rename from frontend/vite/src/core/router.js rename to frontend/src/core/router.js diff --git a/frontend/vite/style.css b/frontend/style.css similarity index 100% rename from frontend/vite/style.css rename to frontend/style.css diff --git a/frontend/vite/vite.config.js b/frontend/vite.config.js similarity index 100% rename from frontend/vite/vite.config.js rename to frontend/vite.config.js diff --git a/run_backend.sh b/run_backend.sh index 2f860d6..0b53c7b 100755 --- a/run_backend.sh +++ b/run_backend.sh @@ -6,4 +6,4 @@ docker volume create db_data docker build -t postgres db/ docker run -d -p 5432:5432 --name postgres --env-file .env -v db_data:/var/lib/postgresql/data postgres -sh backend/django/run-server.sh +sh backend/run-server.sh diff --git a/run_frontend.sh b/run_frontend.sh index b0eb41f..cb6a14d 100755 --- a/run_frontend.sh +++ b/run_frontend.sh @@ -2,7 +2,7 @@ # TEST: 개발 시 로컬 실행용 -cd frontend/vite +cd frontend npm install From 08f7966bac812f36da0cac51e1fabc9ada892a10 Mon Sep 17 00:00:00 2001 From: seungwonme Date: Sun, 4 Aug 2024 22:36:51 +0900 Subject: [PATCH 3/6] chore: Update scripts running on the server --- .python-version | 1 + backend/docker-run-server.sh | 24 ++++++++++++++++++++---- backend/run-server.sh | 24 ++++++++++++++++++++---- run_backend.sh | 9 ++++++--- run_frontend.sh | 8 +------- 5 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 .python-version diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..fa80c9e --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +transcendence diff --git a/backend/docker-run-server.sh b/backend/docker-run-server.sh index c1de956..86099c5 100644 --- a/backend/docker-run-server.sh +++ b/backend/docker-run-server.sh @@ -3,10 +3,16 @@ pip install --upgrade pip if [ -f "requirements.txt" ]; then - pip install -r requirements.txt - echo "Installed packages from requirements.txt." + cnt=$(pip freeze | grep -f requirements.txt | wc -l) + if [ $cnt -lt $(cat requirements.txt | wc -l) ]; then + pip install -r requirements.txt + echo "Installed packages from requirements.txt." + else + echo "Packages from requirements.txt are already installed." + fi else echo "requirements.txt not found." + exit 1 fi echo "Applying migrations..." @@ -14,12 +20,22 @@ python manage.py makemigrations python manage.py migrate # Create a superuser -echo "Creating superuser..." DJANGO_SUPERUSER_USERNAME=$DJANGO_SUPERUSER_USERNAME DJANGO_SUPERUSER_PASSWORD=$DJANGO_SUPERUSER_PASSWORD DJANGO_SUPERUSER_EMAIL=$DJANGO_SUPERUSER_EMAIL -python manage.py createsuperuser --username $DJANGO_SUPERUSER_USERNAME --email $DJANGO_SUPERUSER_EMAIL --noinput || true +USER_EXISTS=$(python manage.py shell -c " +from django.contrib.auth import get_user_model; +User = get_user_model(); +print(User.objects.filter(username='admin').exists()) +") + +echo "USER_EXISTS: $USER_EXISTS" + +if [ "$USER_EXISTS" = "False" ]; then + echo "Creating superuser..." + python manage.py createsuperuser --username $DJANGO_SUPERUSER_USERNAME --email $DJANGO_SUPERUSER_EMAIL --noinput || true +fi echo "Starting development server..." python manage.py runserver 0.0.0.0:8000 diff --git a/backend/run-server.sh b/backend/run-server.sh index 1a76f2a..26765a1 100755 --- a/backend/run-server.sh +++ b/backend/run-server.sh @@ -32,10 +32,16 @@ source $ENV_DIR/bin/activate echo "Virtual environment activated." if [ -f "requirements.txt" ]; then - pip install -r requirements.txt - echo "Installed packages from requirements.txt." + cnt=$(pip freeze | grep -f requirements.txt | wc -l) + if [ $cnt -lt $(cat requirements.txt | wc -l) ]; then + pip install -r requirements.txt + echo "Installed packages from requirements.txt." + else + echo "Packages from requirements.txt are already installed." + fi else echo "requirements.txt not found." + exit 1 fi echo "Applying migrations..." @@ -43,12 +49,22 @@ python manage.py makemigrations python manage.py migrate # Create a superuser -echo "Creating superuser..." DJANGO_SUPERUSER_USERNAME=$DJANGO_SUPERUSER_USERNAME DJANGO_SUPERUSER_PASSWORD=$DJANGO_SUPERUSER_PASSWORD DJANGO_SUPERUSER_EMAIL=$DJANGO_SUPERUSER_EMAIL -python manage.py createsuperuser --username $DJANGO_SUPERUSER_USERNAME --email $DJANGO_SUPERUSER_EMAIL --noinput || true +USER_EXISTS=$(python manage.py shell -c " +from django.contrib.auth import get_user_model; +User = get_user_model(); +print(User.objects.filter(username='admin').exists()) +") + +if [ "$USER_EXISTS" = "False" ]; then + echo "Creating superuser..." + python manage.py createsuperuser --username $DJANGO_SUPERUSER_USERNAME --email $DJANGO_SUPERUSER_EMAIL --noinput || true +fi echo "Starting development server..." +clear + python manage.py runserver localhost:8000 diff --git a/run_backend.sh b/run_backend.sh index 0b53c7b..bc81282 100755 --- a/run_backend.sh +++ b/run_backend.sh @@ -2,8 +2,11 @@ # TEST: 개발 시 로컬 실행용 -docker volume create db_data -docker build -t postgres db/ -docker run -d -p 5432:5432 --name postgres --env-file .env -v db_data:/var/lib/postgresql/data postgres +# Check if the container is already running +if ! docker ps -q -f name=postgres >/dev/null; then + docker volume create db_data + docker build -t postgres db/ + docker run -d -p 5432:5432 --name postgres --env-file .env -v db_data:/var/lib/postgresql/data postgres +fi sh backend/run-server.sh diff --git a/run_frontend.sh b/run_frontend.sh index cb6a14d..38a6b06 100755 --- a/run_frontend.sh +++ b/run_frontend.sh @@ -1,9 +1,3 @@ #!/bin/bash - # TEST: 개발 시 로컬 실행용 - -cd frontend - -npm install - -npm run dev +cd frontend && npm install && npm run dev From e739872cdabe083123ed1b20193e7e1998d31c74 Mon Sep 17 00:00:00 2001 From: seungwonme Date: Sun, 4 Aug 2024 23:08:23 +0900 Subject: [PATCH 4/6] feat: Put the JWT in the cookie --- Makefile | 5 +- backend/login/urls.py | 10 ++++ backend/login/views.py | 75 +++++++++++++++------------ backend/requirements.txt | 8 ++- backend/transcendence/settings.py | 34 ++++++------ backend/transcendence/urls.py | 24 +++------ backend/users/urls.py | 10 ---- docker-compose.yml | 4 ++ frontend/src/components/Home-Login.js | 6 ++- frontend/vite.config.js | 1 - 10 files changed, 91 insertions(+), 86 deletions(-) create mode 100644 backend/login/urls.py diff --git a/Makefile b/Makefile index 2e38507..9472533 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ build: up: @docker-compose -f docker-compose.yml up -d - @echo "🛜 $(FG_GREEN)Connect to $(FG_WHITE)$(UNDERLINE)https://localhost$(RESET) 🛜" + @echo "🛜 $(FG_GREEN)Connect to $(FG_WHITE)$(UNDERLINE)https://localhost:80$(RESET) 🛜" down: @docker-compose -f docker-compose.yml down @@ -51,7 +51,7 @@ stop: start: @echo "$(FG_GREEN)Started$(RESET)" @docker-compose -f docker-compose.yml start - @echo "$(FG_GREEN)Connect to $(FG_WHITE)$(UNDERLINE)http://localhost$(RESET)" + @echo "$(FG_GREEN)Connect to $(FG_WHITE)$(UNDERLINE)http://localhost:80$(RESET)" re: @echo "$(FG_GREEN)Restarted$(RESET)" @@ -70,6 +70,7 @@ clean: fclean: @$(MAKE) down @docker system prune -af --volumes + @docker volume rm transcendence_db_data @echo "🧹 $(FG_BLUE)Fully cleaned up$(RESET) 🧹" .PHONY: all build up down stop start re log clean fclean diff --git a/backend/login/urls.py b/backend/login/urls.py new file mode 100644 index 0000000..6117bb4 --- /dev/null +++ b/backend/login/urls.py @@ -0,0 +1,10 @@ +from django.urls import path +from .views import ( + login, + callback, +) + +urlpatterns = [ + path('login/', login), + path('callback/', callback), +] diff --git a/backend/login/views.py b/backend/login/views.py index 0ec9f0e..312f441 100644 --- a/backend/login/views.py +++ b/backend/login/views.py @@ -1,70 +1,66 @@ -from django.shortcuts import render import requests from django.shortcuts import redirect -from django.shortcuts import render -from django.conf import settings from users.models import User - -# feature01-42OAuth_Login 에서 추가됨 -def login_view(request): - return render(request, 'django/login.html') +from datetime import datetime, timedelta +import jwt +from django.conf import settings +import os +from rest_framework.decorators import api_view +from rest_framework.response import Response +@api_view(["GET"]) def login(request): oauth_url = "https://api.intra.42.fr/oauth/authorize" - client_id = "u-s4t2ud-9bd5c0e972b48a45c2d1d443e8f8a46e8224352693fd09c443212d15919f7521" # 실제 클라이언트 ID로 변경 - redirect_uri = "http://localhost:8000/api/callback" - state = "random_state_string" # CSRF 방지용 랜덤 문자열 - + redirect_uri = "http://localhost:8000/api/callback/" + client_id = os.getenv("OAUTH_CLIENT_ID") + state = os.getenv("OAUTH_STATE") # CSRF 방지용 랜덤 문자열 return redirect(f"{oauth_url}?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&state={state}") +@api_view(["GET"]) def callback(request): - code = request.GET.get('code') + code = request.GET.get("code") if not code: - return redirect('/') # 코드가 없으면 리디렉션 + return redirect("http://localhost:5173") token_url = "https://api.intra.42.fr/oauth/token" - client_id = "u-s4t2ud-9bd5c0e972b48a45c2d1d443e8f8a46e8224352693fd09c443212d15919f7521" # 실제 클라이언트 ID로 변경 - client_secret = "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" # 실제 클라이언트 시크릿으로 변경 - redirect_uri = "http://localhost:8000/api/callback" + redirect_uri = "http://localhost:8000/api/callback/" + client_id = os.getenv("OAUTH_CLIENT_ID") + client_secret = os.getenv("OAUTH_CLIENT_SECRET") data = { - 'grant_type': 'authorization_code', - 'code': code, - 'client_id': client_id, - 'client_secret': client_secret, - 'redirect_uri': redirect_uri, + "grant_type": "authorization_code", + "code": code, + "client_id": client_id, + "client_secret": client_secret, + "redirect_uri": redirect_uri, } + response = requests.post(token_url, data=data) if response.status_code != 200: - return redirect('/') # 오류 발생 시 리디렉션 + return redirect("http://localhost:5173") token_data = response.json() - access_token = token_data.get('access_token') + access_token = token_data.get("access_token") # Access Token을 사용하여 사용자 정보 가져오기 user_info = requests.get("https://api.intra.42.fr/v2/me", headers={"Authorization": f"Bearer {access_token}"}) if user_info.status_code != 200: - return redirect('/') # 사용자 정보 가져오기 실패 시 리디렉션 + return redirect("http://localhost:5173") user_data = user_info.json() # 사용자 정보 처리 (예: DB 저장) - nickname = user_data.get('login') # 42 API에서 사용자 로그인 이름 - img_url = user_data.get('image', {}).get('link') # 42 API에서 사용자 이미지 URL - is_2FA = user_data.get('is_2fa', False) # 2FA 여부 + nickname = user_data.get("login") # 42 API에서 사용자 로그인 이름 + img_url = user_data.get("image", {}).get("link") # 42 API에서 사용자 이미지 URL + is_2FA = user_data.get("is_2fa", False) # 2FA 여부 is_online = False # 기본값으로 설정 (온라인 상태는 API에서 제공하지 않음) # 사용자 정보 저장 또는 업데이트 user, created = User.objects.update_or_create( - nickname=nickname, - defaults={ - 'img_url': img_url, - 'is_2FA': is_2FA, - 'is_online': is_online - } + nickname=nickname, defaults={"img_url": img_url, "is_2FA": is_2FA, "is_online": is_online} ) # 생성된 경우, 추가 로직 (예: 환영 메시지 등) @@ -73,4 +69,15 @@ def callback(request): else: print(f"기존 사용자 업데이트: {nickname}") - return redirect('/') # 로그인 후 리디렉션 + # JWT 토큰 생성 + payload = { + "id": user.user_id, + "nickname": user.nickname, + "exp": datetime.utcnow() + timedelta(hours=24), # 토큰 유효 시간 설정 + } + token = jwt.encode(payload, settings.SECRET_KEY, algorithm="HS256") + + response = redirect("http://localhost:5173") + response.set_cookie("jwt", token, httponly=True, secure=True, samesite='Lax') + + return response diff --git a/backend/requirements.txt b/backend/requirements.txt index 7aaf315..7c3ef6d 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,16 +1,22 @@ asgiref==3.8.1 +certifi==2024.7.4 +charset-normalizer==3.3.2 Django==4.2.14 django-cors-headers==4.4.0 djangorestframework==3.15.2 +djangorestframework-simplejwt==5.3.1 drf-yasg==1.21.7 +idna==3.7 inflection==0.5.1 packaging==24.1 psycopg2-binary==2.9.9 +PyJWT==2.9.0 python-dotenv==1.0.1 pytz==2024.1 PyYAML==6.0.1 +requests==2.31.0 setuptools==71.1.0 sqlparse==0.5.1 typing_extensions==4.12.2 uritemplate==4.1.1 -requests==2.31.0 +urllib3==2.2.2 diff --git a/backend/transcendence/settings.py b/backend/transcendence/settings.py index ce44b55..41ec5a1 100644 --- a/backend/transcendence/settings.py +++ b/backend/transcendence/settings.py @@ -1,27 +1,18 @@ -""" -Django settings for transcendence project. - -Generated by 'django-admin startproject' using Django 4.2.14. - -For more information on this file, see -https://docs.djangoproject.com/en/4.2/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/4.2/ref/settings/ -""" - from pathlib import Path import os +# TEST: 로컬에서 테스트할 때 사용 +from dotenv import load_dotenv + +load_dotenv() # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent - # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-0s%66@!5og-abujy%dd)7og^4xxnmd(2wggfpv)exue6f-p1&w' +SECRET_KEY = os.getenv('SECRET_KEY') # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -41,10 +32,17 @@ 'rest_framework', "corsheaders", 'drf_yasg', + 'rest_framework_simplejwt', "users.apps.UsersConfig", "login.apps.LoginConfig", ] +REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework_simplejwt.authentication.JWTAuthentication', + ) +} + MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', @@ -59,6 +57,10 @@ CORS_ORIGIN_ALLOW_ALL = True # TEST: 모든 도메인 허용 (보안 취약) +CSRF_TRUSTED_ORIGINS = [ + "http://localhost:5173", +] + CORS_ALLOWED_ORIGINS = [ "http://localhost:5173", ] @@ -90,10 +92,6 @@ # Database # https://docs.djangoproject.com/en/4.2/ref/settings/#databases -# TEST: 로컬에서 테스트할 때 사용 -from dotenv import load_dotenv -load_dotenv() - DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', diff --git a/backend/transcendence/urls.py b/backend/transcendence/urls.py index 6abc1ec..46e1346 100644 --- a/backend/transcendence/urls.py +++ b/backend/transcendence/urls.py @@ -1,25 +1,12 @@ -""" -URL configuration for transcendence project. - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/4.2/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: path('', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.urls import include, path - 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) -""" from django.contrib import admin -from django.urls import path, re_path +from django.urls import path, re_path, include +from django.http import HttpResponse from rest_framework import permissions from drf_yasg.views import get_schema_view from drf_yasg import openapi -from django.urls import include + +def index(request): + return HttpResponse("It works!") # Swagger 설정 schema_view = get_schema_view( @@ -37,6 +24,7 @@ # URL 패턴 설정 urlpatterns = [ + path('', index), path('admin/', admin.site.urls), re_path(r'^swagger(?P\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'), path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), diff --git a/backend/users/urls.py b/backend/users/urls.py index bcfd2a6..2da8a41 100644 --- a/backend/users/urls.py +++ b/backend/users/urls.py @@ -3,20 +3,10 @@ get_user, get_user_list, create_user, - - # feature01-42OAuth_Login 에서 추가됨 - login, - callback, - login_view, ) urlpatterns = [ path('user/get/', get_user_list), path('user/get//', get_user), path('user/create//', create_user), - - # feature01-42OAuth_Login 에서 추가됨 - path('login/', login), - path('callback/', callback), - path('login/view/', login_view), ] diff --git a/docker-compose.yml b/docker-compose.yml index 590e64e..db7b017 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -35,6 +35,10 @@ services: - DB_PASSWORD=${DB_PASSWORD} - DB_HOST=${DB_HOST} - DB_PORT=${DB_PORT} + - SECRET_KEY=${SECRET_KEY} + - DJANGO_SUPERUSER_USERNAME=${DJANGO_SUPERUSER_USERNAME} + - DJANGO_SUPERUSER_EMAIL=${DJANGO_SUPERUSER_EMAIL} + - DJANGO_SUPERUSER_PASSWORD=${DJANGO_SUPERUSER_PASSWORD} restart: on-failure # TEST: 테스트를 위해 포트를 열어둠 ports: diff --git a/frontend/src/components/Home-Login.js b/frontend/src/components/Home-Login.js index 719d117..f8c2d03 100644 --- a/frontend/src/components/Home-Login.js +++ b/frontend/src/components/Home-Login.js @@ -13,7 +13,9 @@ export class Login extends Component { setEvent () { this.addEvent('click', '#login', () => { - changeUrl("/main"); + // 백엔드 서버의 로그인 엔드포인트로 리디렉션 + window.location.href = 'http://localhost:8000/api/login'; + changeUrl('/login'); }); } -} \ No newline at end of file +} diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 05ec39f..8e33216 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -9,7 +9,6 @@ export default defineConfig({ // TEST: 평가 시 80번 포트로 변경 (nginx를 거쳐 api를 호출하도록) target: "http://localhost:8000", changeOrigin: true, - rewrite: (path) => path.replace(/^\/api/, ""), }, }, }, From 9a7d8c472294cbc75a67c32eab43fbe5e9065dec Mon Sep 17 00:00:00 2001 From: seungwonme Date: Mon, 5 Aug 2024 02:57:39 +0900 Subject: [PATCH 5/6] feat: Implement 42 OAuth login --- backend/login/urls.py | 2 ++ backend/login/views.py | 27 +++++++++++++++++++++++---- frontend/src/components/Home-Login.js | 24 ++++++++++++++++++++++-- run_backend.sh | 4 ++-- 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/backend/login/urls.py b/backend/login/urls.py index 6117bb4..9e708a9 100644 --- a/backend/login/urls.py +++ b/backend/login/urls.py @@ -2,9 +2,11 @@ from .views import ( login, callback, + validate_token ) urlpatterns = [ path('login/', login), path('callback/', callback), + path('validate/', validate_token), ] diff --git a/backend/login/views.py b/backend/login/views.py index 312f441..b18e46e 100644 --- a/backend/login/views.py +++ b/backend/login/views.py @@ -1,12 +1,14 @@ -import requests from django.shortcuts import redirect +from django.views.decorators.csrf import csrf_exempt +from django.middleware.csrf import get_token +from django.http import JsonResponse +from django.conf import settings from users.models import User +from rest_framework.decorators import api_view from datetime import datetime, timedelta +import requests import jwt -from django.conf import settings import os -from rest_framework.decorators import api_view -from rest_framework.response import Response @api_view(["GET"]) @@ -81,3 +83,20 @@ def callback(request): response.set_cookie("jwt", token, httponly=True, secure=True, samesite='Lax') return response + +@csrf_exempt +def validate_token(request): + # CSRF 토큰 발급 + get_token(request) + + token = request.COOKIES.get('jwt') + if not token: + return JsonResponse({"isValid": False}) + + try: + payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"]) + return JsonResponse({"isValid": True, "user": payload}) + except jwt.ExpiredSignatureError: + return JsonResponse({"isValid": False, "error": "Token has expired"}) + except jwt.InvalidTokenError: + return JsonResponse({"isValid": False, "error": "Invalid token"}) diff --git a/frontend/src/components/Home-Login.js b/frontend/src/components/Home-Login.js index f8c2d03..662d885 100644 --- a/frontend/src/components/Home-Login.js +++ b/frontend/src/components/Home-Login.js @@ -13,9 +13,29 @@ export class Login extends Component { setEvent () { this.addEvent('click', '#login', () => { - // 백엔드 서버의 로그인 엔드포인트로 리디렉션 + // 로그인 요청 window.location.href = 'http://localhost:8000/api/login'; - changeUrl('/login'); + }); + + // 유효성 검사 요청 + this.checkAuth(); + } + + checkAuth() { + fetch('http://localhost:8000/api/validate', { + method: 'GET', + credentials: 'include', // 쿠키를 포함하여 요청 + }) + .then(response => response.json()) + .then(data => { + if (data.isValid) { + changeUrl('/main'); + } else { + console.error('Authentication failed'); + } + }) + .catch(error => { + console.error('Error:', error); }); } } diff --git a/run_backend.sh b/run_backend.sh index bc81282..73d46f7 100755 --- a/run_backend.sh +++ b/run_backend.sh @@ -2,8 +2,8 @@ # TEST: 개발 시 로컬 실행용 -# Check if the container is already running -if ! docker ps -q -f name=postgres >/dev/null; then +# Check if the container is not running +if [ -z "$(docker ps -q -f name=postgres)" ]; then docker volume create db_data docker build -t postgres db/ docker run -d -p 5432:5432 --name postgres --env-file .env -v db_data:/var/lib/postgresql/data postgres From 4ffdc3b30d31edf1f4c95a367ce24ca6e3f427ad Mon Sep 17 00:00:00 2001 From: seungwonme Date: Mon, 5 Aug 2024 03:21:31 +0900 Subject: [PATCH 6/6] feat: Add email for 2FA to the user model --- backend/login/views.py | 7 ++++++- backend/transcendence/settings.py | 4 ++-- backend/users/migrations/0001_initial.py | 3 ++- backend/users/models.py | 1 + clear_db.sh | 3 +++ 5 files changed, 14 insertions(+), 4 deletions(-) create mode 100755 clear_db.sh diff --git a/backend/login/views.py b/backend/login/views.py index b18e46e..35549da 100644 --- a/backend/login/views.py +++ b/backend/login/views.py @@ -56,13 +56,18 @@ def callback(request): # 사용자 정보 처리 (예: DB 저장) nickname = user_data.get("login") # 42 API에서 사용자 로그인 이름 + email = user_data.get("email") # 42 API에서 사용자 이메일 img_url = user_data.get("image", {}).get("link") # 42 API에서 사용자 이미지 URL is_2FA = user_data.get("is_2fa", False) # 2FA 여부 is_online = False # 기본값으로 설정 (온라인 상태는 API에서 제공하지 않음) # 사용자 정보 저장 또는 업데이트 user, created = User.objects.update_or_create( - nickname=nickname, defaults={"img_url": img_url, "is_2FA": is_2FA, "is_online": is_online} + nickname=nickname, defaults={ + "email": email, + "img_url": img_url, + "is_2FA": is_2FA, + "is_online": is_online} ) # 생성된 경우, 추가 로직 (예: 환영 메시지 등) diff --git a/backend/transcendence/settings.py b/backend/transcendence/settings.py index 41ec5a1..ba70d33 100644 --- a/backend/transcendence/settings.py +++ b/backend/transcendence/settings.py @@ -1,6 +1,6 @@ from pathlib import Path import os -# TEST: 로컬에서 테스트할 때 사용 +# TEST: 로컬에서 테스트할 때 사용, docker-compose 이용 시 환경변수로 알아서 설정됨 from dotenv import load_dotenv load_dotenv() @@ -73,7 +73,7 @@ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', # feature01-42OAuth_Login 에서 추가됨 원래 [] 로 비어있었음 - 'DIRS': [os.path.join(BASE_DIR, 'templates')], + 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ diff --git a/backend/users/migrations/0001_initial.py b/backend/users/migrations/0001_initial.py index 32e3aae..46f36f5 100644 --- a/backend/users/migrations/0001_initial.py +++ b/backend/users/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.14 on 2024-07-28 11:28 +# Generated by Django 4.2.14 on 2024-08-04 18:19 from django.db import migrations, models import django.db.models.deletion @@ -28,6 +28,7 @@ class Migration(migrations.Migration): fields=[ ('user_id', models.AutoField(primary_key=True, serialize=False)), ('nickname', models.CharField(max_length=255)), + ('email', models.EmailField(max_length=255)), ('img_url', models.URLField(blank=True)), ('is_2FA', models.BooleanField(default=False)), ('is_online', models.BooleanField(default=False)), diff --git a/backend/users/models.py b/backend/users/models.py index 360175e..424a631 100644 --- a/backend/users/models.py +++ b/backend/users/models.py @@ -4,6 +4,7 @@ class User(models.Model): user_id = models.AutoField(primary_key=True) nickname = models.CharField(max_length=255) + email = models.EmailField(max_length=255) img_url = models.URLField(blank=True) is_2FA = models.BooleanField(default=False) is_online = models.BooleanField(default=False) diff --git a/clear_db.sh b/clear_db.sh new file mode 100755 index 0000000..201bbcd --- /dev/null +++ b/clear_db.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +docker rm -f postgres && docker volume rm db_data