Skip to content

Commit

Permalink
๐Ÿ› Fix : ์†Œ์…œ๋กœ๊ทธ์ธ ์—๋Ÿฌ ์ˆ˜์ •
Browse files Browse the repository at this point in the history
  • Loading branch information
seon022 committed Dec 9, 2024
1 parent b9b99b6 commit 1a17032
Show file tree
Hide file tree
Showing 10 changed files with 65 additions and 69 deletions.
30 changes: 15 additions & 15 deletions src/app/(empty-layout)/(auth)/login/callback/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,30 @@ export default function LoginCallbackPage() {
useEffect(() => {
const handleKakaoLoginCallback = async () => {
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
const state = urlParams.get('state');

// state ๊ฒ€์ฆ
const savedState = localStorage.getItem('kakao_oauth_state');
if (!state || state !== savedState) {
toast.error('์ธ์ฆ ์ƒํƒœ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.');
router.push('/login');
return;
}
const accessToken = urlParams.get('accessToken');
const refreshToken = urlParams.get('refreshToken');
const userId = urlParams.get('userId');

if (!code) {
toast.error('์œ ํšจํ•˜์ง€ ์•Š์€ ์ธ์ฆ ์ •๋ณด์ž…๋‹ˆ๋‹ค.');
// ํ† ํฐ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
if (!accessToken || !refreshToken || !userId) {
toast.error('์œ ํšจํ•˜์ง€ ์•Š์€ ๋กœ๊ทธ์ธ ์ •๋ณด์ž…๋‹ˆ๋‹ค.');
router.push('/login');
return;
}

try {
const result = await userService.kakaoLoginCallback(code, state);
await socialLoginComplete(result);
const loginResult = {
authentication: 'Bearer',
access_token: accessToken,
refresh_token: refreshToken,
userId
};

// state ์ œ๊ฑฐ
localStorage.removeItem('kakao_oauth_state');
// ์†Œ์…œ ๋กœ๊ทธ์ธ ์™„๋ฃŒ ์ฒ˜๋ฆฌ
await socialLoginComplete(loginResult);

localStorage.removeItem('kakao_oauth_state');
toast.success('์นด์นด์˜ค ๋กœ๊ทธ์ธ ์„ฑ๊ณต');
router.push('/');
} catch (error) {
Expand Down
4 changes: 2 additions & 2 deletions src/app/(empty-layout)/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Link from 'next/link';
import { toast } from 'react-toastify';
import useRedirect from '@/features/auth/hooks/useRedirect';
import LoginContainer from '@/features/auth/ui/LoginContainer';
import { useAuthStore } from '@/entities/user';
import { useAuthStore } from '@/entities/User';

export default function LoginPage() {
const { isAuthenticated, userId, tokens, kakaoLogin } = useAuthStore();
Expand All @@ -14,7 +14,7 @@ export default function LoginPage() {
const handleKakaoLogin = async () => {
try {
// ์ƒํƒœ(state) ์ƒ์„ฑ ๋ฐ ์ €์žฅ
const state = crypto.randomUUID();
const state = window.btoa(crypto.randomUUID());
localStorage.setItem('kakao_oauth_state', state);

// ์นด์นด์˜ค ๋กœ๊ทธ์ธ URL๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
Expand Down
15 changes: 11 additions & 4 deletions src/entities/User/api/userService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,20 @@ export const userService = {
throw error;
}
},
kakaoLoginCallback: async (code: string, state: string) => {
kakaoLoginCallback: async (
code: string,
state: string,
fcmToken?: string
) => {
try {
const response = await axiosInstance.post(
`${process.env.NEXT_PUBLIC_API_URL}/api/oauth2/kakao/callback`,
{ code, state }
{
code,
state,
fcmToken
}
);

return {
authentication: 'Bearer',
userId: response.data.userId,
Expand Down Expand Up @@ -117,7 +124,7 @@ export const userService = {

logout: async () => {
try {
await api.user.logout();
await api.user.logout('Bearer');
} catch (error) {
if (axios.isAxiosError(error)) {
const errorResponse = error.response?.data as ErrorResponseDTO;
Expand Down
33 changes: 25 additions & 8 deletions src/entities/User/model/store/authStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,27 +93,45 @@ export const useAuthStore = create<AuthState>()(
},
socialLoginComplete: async (loginResponse: {
authentication: string;
access_token: string;
refresh_token: string;
accessToken?: string;
refreshToken?: string;
userId: string;
}) => {
// ๊ธฐ์กด ๋กœ๊ทธ์ธ ์™„๋ฃŒ ๋กœ์ง๊ณผ ๋™์ผ
// ํ‚ค ์ด๋ฆ„ ์œ ์—ฐํ•˜๊ฒŒ ์ฒ˜๋ฆฌ
const access_token = loginResponse.accessToken;
const refresh_token = loginResponse.refreshToken;

// ์ฟ ํ‚ค์— ์‚ฌ์šฉ์ž ํ† ํฐ ์ •๋ณด ์ €์žฅ
document.cookie = `auth-storage=${JSON.stringify({
state: {
userId: loginResponse.userId,
tokens: {
access_token: loginResponse.access_token,
refresh_token: loginResponse.refresh_token
access_token,
refresh_token
},
isAuthenticated: true
}
})}; path=/; secure; samesite=strict; max-age=86400`;

// ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์‚ฌ์šฉ์ž ์ •๋ณด ์ €์žฅ
localStorage.setItem(
'auth-storage',
JSON.stringify({
userId: loginResponse.userId,
tokens: {
access_token,
refresh_token
},
isAuthenticated: true
})
);

// Zustand ์Šคํ† ์–ด ์ƒํƒœ ์—…๋ฐ์ดํŠธ
set({
userId: loginResponse.userId,
tokens: {
access_token: loginResponse.access_token,
refresh_token: loginResponse.refresh_token
access_token,
refresh_token
},
isAuthenticated: true,
isLoading: false,
Expand All @@ -122,7 +140,6 @@ export const useAuthStore = create<AuthState>()(

return true;
},

join: async (joinData: UserJoinDTO) => {
set({ isLoading: true, error: null });

Expand Down
2 changes: 1 addition & 1 deletion src/entities/User/model/types/AuthState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export interface AuthState {
login: (loginData: UserLoginDTO) => Promise<boolean>;
socialLogin: (provider: SocialProvider) => Promise<boolean>;
join: (joinData: UserJoinDTO) => Promise<boolean>;
logout: () => void;
logout: (authorization: string) => Promise<boolean>;
refreshToken: () => Promise<boolean>;
deleteUser: () => Promise<boolean>;
socialLoginComplete: (loginResponse: LoginResponse) => Promise<boolean>;
Expand Down
6 changes: 2 additions & 4 deletions src/features/auth/ui/LoginContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
import { useEffect, useState } from 'react';
import LoginForm from './LoginForm';
import { useRouter } from 'next/navigation';
import { useAuthStore } from '@/entities/user';
import ErrorMessage from '@/shared/ui/components/Error/ErrorMsg';
import { requestNotificationPermission } from '@/shared/lib/firebase';
import { useAuthStore } from '@/entities/User';

export default function LoginContainer() {
const router = useRouter();
Expand Down Expand Up @@ -33,8 +32,7 @@ export default function LoginContainer() {
const success = await login({
email,
password,
fcmToken,
passwordEmpty: true
fcmToken
});

if (success) {
Expand Down
14 changes: 6 additions & 8 deletions src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,24 @@ import { NextResponse, type NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
const pathname = request.nextUrl.pathname;
const authToken = request.cookies.get('auth-storage');
const authToken = request.cookies.get('auth-storage')?.value;

// ๊ณต๊ฐœ ๊ฒฝ๋กœ ์ •์˜
const publicPaths = ['/login', '/'];
console.log('Pathname:', pathname);
console.log('Auth Token:', authToken);

// ์ธ์ฆ์ด ํ•„์š”ํ•œ ๊ฒฝ๋กœ
const protectedPaths = ['/profile'];

if (publicPaths.includes(pathname) && authToken) {
return NextResponse.redirect(new URL('/', request.url));
}

if (protectedPaths.includes(pathname) && !authToken) {
return NextResponse.redirect(new URL('/login', request.url));
}

console.log('Pathname222222:', pathname);
console.log('Auth Token222222222:', authToken);
return NextResponse.next();
}

// ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์ ์šฉ๋  ๊ฒฝ๋กœ
export const config = {
matcher: ['/login', '/profile']
matcher: ['/profile']
};
1 change: 0 additions & 1 deletion src/mocks/handlers/authHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ export const authHandlers = [
const verificationCode = faker.string.numeric(6);

emailVerificationCodes[email] = verificationCode;
console.log(`Verification code for ${email}: ${verificationCode}`);

return HttpResponse.json(null, { status: 200 });
}),
Expand Down
2 changes: 1 addition & 1 deletion src/widgets/header/ui/CustomHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface CustomHeaderProps {

export const CustomHeader = ({ title, rightButton }: CustomHeaderProps) => {
const router = useRouter();
const pathname = usePathname() ?? '/'; // null์ผ ๊ฒฝ์šฐ ๊ธฐ๋ณธ๊ฐ’ '/' ์‚ฌ์šฉ
const pathname = usePathname() ?? '/';

const handleGoBack = () => {
const pathSegments = pathname.split('/').filter(Boolean);
Expand Down
27 changes: 2 additions & 25 deletions src/widgets/header/ui/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,9 @@ const getDefaultTitle = (pathname: string) => {
};

export const Header = ({ detailTitle }: HeaderProps) => {
const { hasNewNotifications } = useNotifications();
const router = useRouter();
const pathname = usePathname();

const notificationIcon = hasNewNotifications
? '/icons/notification-new.png'
: '/icons/notification.png';

const isDetailPage = DETAIL_PAGE_PATTERNS.some(pattern =>
pathname?.includes(pattern)
);
Expand All @@ -33,7 +28,7 @@ export const Header = ({ detailTitle }: HeaderProps) => {
if (isDetailPage) {
return (
<header className="fixed left-0 right-0 top-0 z-40 mx-auto h-[56px] w-full bg-white">
<div className="md:px-6 relative flex h-full w-full items-center justify-center px-4">
<div className="relative flex h-full w-full items-center justify-center px-4 md:px-6">
<button
className="absolute left-[1.5rem] flex cursor-pointer items-center rounded-lg border border-none border-gray-200 bg-none p-2"
onClick={() => router.back()}>
Expand All @@ -55,7 +50,7 @@ export const Header = ({ detailTitle }: HeaderProps) => {
// ๊ธฐ๋ณธ ํ—ค๋”
return (
<header className="fixed left-0 right-0 top-0 z-40 mx-auto h-[56px] w-full bg-white">
<div className="md:px-6 mx-auto flex h-full w-full max-w-[600px] items-center justify-between px-4">
<div className="mx-auto flex h-full w-full max-w-[600px] items-center justify-between px-4 md:px-6">
<Link
href="/"
className="flex items-center">
Expand All @@ -68,16 +63,6 @@ export const Header = ({ detailTitle }: HeaderProps) => {
</Link>

<div className="flex items-center justify-center gap-2">
<button
className="flex h-16 w-16 items-center justify-center rounded-lg border border-gray-200"
onClick={() => router.push('/notifications')}>
<Image
src={notificationIcon}
alt="์•Œ๋ฆผ"
width={26}
height={26}
/>
</button>
<button
className="flex h-16 w-16 items-center justify-center rounded-lg border border-gray-200"
onClick={() => router.push('/calendar')}>
Expand All @@ -88,14 +73,6 @@ export const Header = ({ detailTitle }: HeaderProps) => {
height={22}
/>
</button>
<button className="flex h-16 w-16 items-center justify-center rounded-lg border border-gray-200">
<Image
src="/icons/search.png"
alt="๊ฒ€์ƒ‰"
width={22}
height={22}
/>
</button>
</div>
</div>
</header>
Expand Down

0 comments on commit 1a17032

Please sign in to comment.