Skip to content

Commit

Permalink
refactor: 백엔드 코드 모듈화 및 http method 별 분리
Browse files Browse the repository at this point in the history
  • Loading branch information
pozafly committed Jul 25, 2023
1 parent 6010ea5 commit d496003
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 164 deletions.
21 changes: 21 additions & 0 deletions src/backend/auth/httpMethods/DELETE.ts
@@ -0,0 +1,21 @@
import { setCookie } from '@/backend/utils/cookieUtils.ts';
import { readJSONFile, writeFile } from '@/backend/utils/fileUtils.ts';
import { AxiosError } from 'axios';
import { NextApiRequest, NextApiResponse } from 'next';

export function DELETE(
req: NextApiRequest,
res: NextApiResponse<AxiosError | { message: string }>
) {
const accessToken = req.cookies.Authorization;

const jsonTokens = readJSONFile();
const index = jsonTokens.findIndex(v => v.access_token === accessToken);
if (index > -1) {
jsonTokens.splice(index, 1);
}
writeFile(jsonTokens);
setCookie(res, 'Authorization', 'deleted', { maxAge: -1, path: '/' });

res.status(200).json({ message: 'success' });
}
17 changes: 17 additions & 0 deletions src/backend/auth/httpMethods/GET.ts
@@ -0,0 +1,17 @@
import { GoogleUrl } from '@/backend/auth/interfaces.ts';
import { GOOGLE_INFO } from '@/backend/constants/google.ts';
import { oauth2Client } from '@/backend/utils/authUtils.ts';
import { AxiosError } from 'axios';
import { NextApiRequest, NextApiResponse } from 'next';

const authorizationUrl: string = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: GOOGLE_INFO.SCOPE,
});

export function GET(
req: NextApiRequest,
res: NextApiResponse<GoogleUrl | AxiosError>
) {
res.status(200).json({ location: authorizationUrl });
}
107 changes: 107 additions & 0 deletions src/backend/auth/httpMethods/POST.ts
@@ -0,0 +1,107 @@
import { GoogleUrl, JSONFile, Login } from '@/backend/auth/interfaces.ts';
import { oauth2Client } from '@/backend/utils/authUtils.ts';
import { setCookie } from '@/backend/utils/cookieUtils.ts';
import {
checkSameToken,
readJSONFile,
writeFile,
} from '@/backend/utils/fileUtils.ts';
import { AxiosError } from 'axios';
import { NextApiRequest, NextApiResponse } from 'next';

let hasGetTokenRequest = false;

export async function POST(
req: NextApiRequest,
res: NextApiResponse<GoogleUrl | Login | Response | AxiosError>
) {
const body = req.body;

switch (body.type) {
case 'GET_TOKEN': {
if (hasGetTokenRequest) {
res.status(429).end();
hasGetTokenRequest = false;
return;
}
hasGetTokenRequest = true;

const { tokens } = await oauth2Client.getToken(body.code);

oauth2Client.setCredentials(tokens);
writeFile(checkSameToken(tokens));

setCookie(res, 'Authorization', tokens.access_token, {
httpOnly: true,
sameSite: process.env.NEXT_PUBLIC_MODE !== 'development',
domain:
process.env.NEXT_PUBLIC_MODE !== 'development'
? process.env.NEXT_PUBLIC_DOMAIN_URI
: '',
path: '/',
maxAge: 60 * 60 * 24 * 20, // 20일
});
res.status(200).json({ token: tokens.access_token || '' });
break;
}

case 'GET_TOKEN_BY_REFRESH_TOKEN': {
if (!Object.hasOwn(req.cookies, 'Authorization')) {
res.status(404).json({
message: 'not found',
isAxiosError: true,
location: 'server',
name: 'AxiosError',
});
return;
}

const accessToken = req.cookies.Authorization;
const jsonTokens: JSONFile[] = readJSONFile();
const targetIndex = jsonTokens.findIndex(
token => token.access_token === accessToken
);

if (targetIndex < 0) {
res.status(404).json({
message: 'not found',
isAxiosError: true,
location: 'server',
name: 'AxiosError',
});
return;
}

// @ts-ignore
const { tokens } = await oauth2Client.refreshToken(
jsonTokens[targetIndex].refresh_token
);

jsonTokens[targetIndex] = {
...jsonTokens[targetIndex],
access_token: tokens.access_token || '',
};

writeFile(jsonTokens);

setCookie(res, 'Authorization', tokens.access_token, {
httpOnly: true,
sameSite: process.env.NEXT_PUBLIC_MODE !== 'development',
domain:
process.env.NEXT_PUBLIC_MODE !== 'development'
? process.env.NEXT_PUBLIC_DOMAIN_URI
: '',
path: '/',
maxAge: 60 * 60 * 24 * 20, // 20일
});

oauth2Client.setCredentials(tokens);
res.status(200).json({ token: tokens.access_token || '' });
break;
}

default:
res.status(404).end();
break;
}
}
7 changes: 7 additions & 0 deletions src/backend/auth/index.ts
@@ -0,0 +1,7 @@
export * from '@/backend/auth/httpMethods/GET';
export * from '@/backend/auth/httpMethods/POST';
export * from '@/backend/auth/httpMethods/DELETE';

export type * from '@/backend/auth/httpMethods/GET';
export type * from '@/backend/auth/httpMethods/POST';
export type * from '@/backend/auth/httpMethods/DELETE';
25 changes: 25 additions & 0 deletions src/backend/auth/interfaces.ts
@@ -0,0 +1,25 @@
export interface JSONFile {
access_token: string;
refresh_token: string;
user_email: string;
}

export interface Credentials {
refresh_token?: string | null;
expiry_date?: number | null;
access_token?: string | null;
token_type?: string | null;
id_token?: string | null;
scope?: string;
user_email?: string | null;
}

export interface GoogleUrl {
location: string;
}
export interface Login {
token: string;
}
export interface Response {
message: string;
}
3 changes: 0 additions & 3 deletions src/backend/constants.ts → src/backend/constants/google.ts
Expand Up @@ -6,9 +6,6 @@ export const GOOGLE_INFO = {
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/userinfo.email',
'openid',
// 'https://www.googleapis.com/auth/documents',
// 'https://www.googleapis.com/auth/drive.file',
// 'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.appdata',
],
};
8 changes: 8 additions & 0 deletions src/backend/utils/authUtils.ts
@@ -0,0 +1,8 @@
import { google } from 'googleapis';
import { GOOGLE_INFO } from '@/backend/constants/google.ts';

export const oauth2Client = new google.auth.OAuth2(
GOOGLE_INFO.GOOGLE_ID,
GOOGLE_INFO.GOOGLE_SECRET,
GOOGLE_INFO.REDIRECT_URI
);
File renamed without changes.
31 changes: 8 additions & 23 deletions src/backend/authUtils.ts → src/backend/utils/fileUtils.ts
@@ -1,28 +1,20 @@
import fs from 'fs';
import jwtDecode from 'jwt-decode';

export interface JSONFile {
access_token: string;
refresh_token: string;
user_email: string;
}

export interface Credentials {
refresh_token?: string | null;
expiry_date?: number | null;
access_token?: string | null;
token_type?: string | null;
id_token?: string | null;
scope?: string;
user_email?: string | null;
}
import { Credentials, JSONFile } from '@/backend/auth/interfaces.ts';

export const readJSONFile: () => JSONFile[] = () => {
const dataJSON =
fs.readFileSync(process.env.TOKEN_JSON_PATH as string).toString() || '[]';
return JSON.parse(dataJSON);
};

export const writeFile = (tokens: JSONFile[]) => {
fs.writeFileSync(
process.env.TOKEN_JSON_PATH as string,
JSON.stringify(tokens)
);
};

export const checkSameToken = (tokens: Credentials) => {
const jsonTokens: JSONFile[] = readJSONFile();
const userEmail = jwtDecode<{ email: string }>(
Expand All @@ -48,10 +40,3 @@ export const checkSameToken = (tokens: Credentials) => {
}
return jsonTokens;
};

export const writeFile = (tokens: JSONFile[]) => {
fs.writeFileSync(
process.env.TOKEN_JSON_PATH as string,
JSON.stringify(tokens)
);
};

0 comments on commit d496003

Please sign in to comment.