From b36642532f662524c9c6eb18208c1074feddb9de Mon Sep 17 00:00:00 2001 From: 0xC0FFE2 Date: Wed, 5 Feb 2025 04:10:18 +0900 Subject: [PATCH] =?UTF-8?q?chore=20:=20api=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ProtectedRoute.tsx | 19 ++---- src/services/AuthService.ts | 106 ++++++++++++++++-------------- src/services/RegisterService.ts | 38 +++-------- src/types/Auth.ts | 14 ++-- 4 files changed, 80 insertions(+), 97 deletions(-) diff --git a/src/components/ProtectedRoute.tsx b/src/components/ProtectedRoute.tsx index b0e86f8..d47993e 100644 --- a/src/components/ProtectedRoute.tsx +++ b/src/components/ProtectedRoute.tsx @@ -1,19 +1,10 @@ -import React, { ReactNode } from 'react'; +import React from 'react'; import { Navigate } from 'react-router-dom'; import Cookies from 'js-cookie'; -interface ProtectedProps { - children: ReactNode; -} - -const ProtectedRoute = ({ children }: ProtectedProps) => { - const userCookie = Cookies.get("SYS-REFRESH"); - - if (!userCookie) { - return ; - } - - return children; +const ProtectedRoute = ({ children }: { children: React.ReactNode }) => { + const refreshToken = Cookies.get("refresh_token"); + return refreshToken ? children : ; }; -export default ProtectedRoute; +export default ProtectedRoute; \ No newline at end of file diff --git a/src/services/AuthService.ts b/src/services/AuthService.ts index 972b62e..c53f82e 100644 --- a/src/services/AuthService.ts +++ b/src/services/AuthService.ts @@ -1,81 +1,89 @@ -import { LoginFormData, AuthResponse } from "../types/Auth"; +import Cookies from 'js-cookie'; + +import { AuthResponse, UserProfile } from "../types/Auth"; import { AuthType } from "./dto/request/AuthType"; import { LoginRequest } from "./dto/request/LoginRequest"; import { loginRequestViaApp } from "./dto/request/LoginRequestViaApp"; import { loginRequestViaPin } from "./dto/request/LoginRequestViaPin"; -import { RequestType } from "./dto/request/RequestType"; -import { LoginResponse } from "./dto/response/LoginResponse"; import SERVICE_API_URL from "./ServiceEndPoint"; const BASE_URL = SERVICE_API_URL.BASE_URL; export class AuthService { - static async execute(data: LoginRequest): Promise { - let endpoint = ""; - - if (data.requestType === RequestType.DASHBOARD &&data.authType === AuthType.APP) { - endpoint = `${BASE_URL}/auth/app-login`; - } else if (data.requestType === RequestType.DASHBOARD && data.authType === AuthType.PIN) { - endpoint = `${BASE_URL}/auth/login`; - } else if (data.requestType === RequestType.OAUTH &&data.authType === AuthType.APP) { - endpoint = `${BASE_URL}/oauth/app-login`; - } else { - endpoint = `${BASE_URL}/oauth/login`; - } - - console.log(endpoint); - console.log(data); - - const requestBody = this.getRequestDtoByAuthType(data); + static async login(data: LoginRequest): Promise { + const endpoint = `${BASE_URL}/auth/login`; + const requestBody = this.buildRequestBody(data); const response = await fetch(endpoint, { method: "POST", - headers: { - "Content-Type": "application/json", - }, + headers: { "Content-Type": "application/json" }, body: JSON.stringify(requestBody), - mode: 'cors', }); const result = await response.json(); - + if (!response.ok) { - throw new Error(result.message || "로그인 중 오류가 발생했습니다."); - } - - if (data.requestType !== RequestType.DASHBOARD) { - this.handleOAuthSuccess(result, data.redirectUrl); - return; + throw new Error(result.message || "로그인 실패"); } this.storeTokens(result); window.location.href = data.redirectUrl; } - private static getRequestDtoByAuthType(data: LoginRequest): any { - if (data.authType === AuthType.APP) { - return loginRequestViaApp(data); - } else { - return loginRequestViaPin(data); - } + static async reissueToken(): Promise { + const refreshToken = Cookies.get("refresh_token"); + if (!refreshToken) throw new Error("No refresh token"); + + const response = await fetch(`${BASE_URL}/auth/reissue`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ refreshToken }), + }); + + const result = await response.json(); + if (!response.ok) throw new Error(result.message || "토큰 재발급 실패"); + + this.storeTokens(result); + return result; } - private static handleOAuthSuccess(result: any, redirectUrl?: string): void { - if (!redirectUrl) { - throw new Error("리디렉션 URL이 필요합니다."); - } + // 사용자 프로필 조회 + static async getProfile(): Promise { + const response = await this.authFetch(`${BASE_URL}/auth/userinfo`); + return response.json(); + } - const authCode = result.code; - if (!authCode) { - throw new Error("응답에 인증 코드가 포함되어 있지 않습니다."); + // 인증된 요청 처리 래퍼 + private static async authFetch(input: RequestInfo, init?: RequestInit): Promise { + let accessToken = Cookies.get("access_token"); + let response = await fetch(input, { + ...init, + headers: { ...init?.headers, Authorization: `Bearer ${accessToken}` }, + }); + + if (response.status === 401) { + await this.reissueToken(); + accessToken = Cookies.get("access_token"); + response = await fetch(input, { + ...init, + headers: { ...init?.headers, Authorization: `Bearer ${accessToken}` }, + }); } + return response; + } - const redirectWithAuthCode = `${redirectUrl}?AUTH_CODE=${authCode}`; - window.location.href = redirectWithAuthCode; + private static buildRequestBody(data: LoginRequest) { + if (data.authType === AuthType.APP) { + // loginRequestViaApp 사용 + return loginRequestViaApp(data); + } else { + // loginRequestViaPin 사용 + return loginRequestViaPin(data); + } } - private static storeTokens(result: LoginResponse): void { - document.cookie = `access_token=${result.access_token}; path=/; secure; HttpOnly`; - document.cookie = `refresh_token=${result.refresh_token}; path=/; secure; HttpOnly`; + private static storeTokens(tokens: AuthResponse) { + Cookies.set("access_token", tokens.access_token, { secure: true, expires: 1 }); + Cookies.set("refresh_token", tokens.refresh_token, { secure: true, expires: 7 }); } } diff --git a/src/services/RegisterService.ts b/src/services/RegisterService.ts index 164933f..6a2578a 100644 --- a/src/services/RegisterService.ts +++ b/src/services/RegisterService.ts @@ -3,44 +3,24 @@ const BASE_URL = SERVICE_API_URL.BASE_URL; export class RegisterService { static async register(data: { - redirectUrl?: string; email: string; password: string; name: string; birthDate: string; pin: string; - }): Promise { + redirectUrl?: string; + }) { const deviceToken = window.nanu_androidgw?.devicetoken || "WEB_NONE"; - const requestBody = { - deviceToken: deviceToken, - pin: data.pin, - password: data.password, - name: data.name, - email: data.email, - birthDate: data.birthDate, - }; - - const endpoint = `${BASE_URL}/auth/register`; - - const response = await fetch(endpoint, { + + const response = await fetch(`${BASE_URL}/auth/register`, { method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(requestBody), - mode: "cors", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ ...data, deviceToken }), }); const result = await response.json(); + if (!response.ok) throw new Error(result.message || "회원가입 실패"); - if (!response.ok) { - throw new Error(result.message || "회원가입 중 오류가 발생했습니다."); - } - - if (data.redirectUrl) { - window.location.href = data.redirectUrl; - } else { - window.location.href = "/home"; - } + window.location.href = data.redirectUrl || "/login"; } -} +} \ No newline at end of file diff --git a/src/types/Auth.ts b/src/types/Auth.ts index 83de863..936838f 100644 --- a/src/types/Auth.ts +++ b/src/types/Auth.ts @@ -5,13 +5,11 @@ export interface LoginFormData { } export interface AuthResponse { - token: string; - user: { - id: string; - email: string; - }; + access_token: string; + refresh_token: string; } + export interface RegisterFormData { email: string; password: string; @@ -22,3 +20,9 @@ export interface RegisterFormData { confirmPin: string; termsAccepted: boolean; } + +export interface UserProfile { + email: string; + name: string; + accountStatus: boolean; +} \ No newline at end of file