From 5285387de765efd838f84bca51ceb584a22036fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8E=E1=85=AC=E1=84=8C=E1=85=AE=E1=86=AB=E1=84=8B?= =?UTF-8?q?=E1=85=A7=E1=86=BC?= Date: Wed, 2 Nov 2022 21:21:38 +0900 Subject: [PATCH 1/4] backup --- libs/middlewares/authMiddleware.ts | 37 +++ libs/middlewares/authWithRefreshToken.ts | 45 ++++ libs/middlewares/isLogin.ts | 32 +++ libs/middlewares/validation.ts | 29 +++ package-lock.json | 210 ++++++++++++++++++ package.json | 4 + pages/api/login.ts | 47 ---- pages/api/middlewares/_authNoRefreshToken.ts | 28 --- pages/api/middlewares/authWithRefreshToken.ts | 39 ---- pages/api/user/_isLogin.ts | 37 --- pages/api/user/login.ts | 26 +-- pages/api/user/signup.ts | 55 +++-- prisma/schema.prisma | 19 +- 13 files changed, 399 insertions(+), 209 deletions(-) create mode 100644 libs/middlewares/authMiddleware.ts create mode 100644 libs/middlewares/authWithRefreshToken.ts create mode 100644 libs/middlewares/isLogin.ts create mode 100644 libs/middlewares/validation.ts delete mode 100644 pages/api/login.ts delete mode 100644 pages/api/middlewares/_authNoRefreshToken.ts delete mode 100644 pages/api/middlewares/authWithRefreshToken.ts delete mode 100644 pages/api/user/_isLogin.ts diff --git a/libs/middlewares/authMiddleware.ts b/libs/middlewares/authMiddleware.ts new file mode 100644 index 0000000..74f287e --- /dev/null +++ b/libs/middlewares/authMiddleware.ts @@ -0,0 +1,37 @@ +import { NextRequest, NextFetchEvent, NextResponse } from "next/server"; +import client from "../client"; +import jwt from "jsonwebtoken" +import 'dotenv/config' + +const secret_key = process.env.SECRET_KEY || ""; +export async function middleware( + req: NextRequest, + ev: NextFetchEvent, +){ + try { + if(req.cookies.has('accessToken')){ + const accessToken = req.cookies.get('accessToken'); + if(accessToken !== undefined){ + jwt.verify(accessToken, secret_key, (err, decoded) => { + if(err){ + return new Response( + JSON.stringify({err}), + { status: 401 }, + ); + }; + return NextResponse.next(); + }) + }else{ + return new Response( + JSON.stringify({"message":"로그인이 필요한 기능입니다."}), + { status: 401 }, + ); + } + } + } catch (error:any) { + return new Response( + JSON.stringify({error}), + { status: 401 }, + ); + } +} diff --git a/libs/middlewares/authWithRefreshToken.ts b/libs/middlewares/authWithRefreshToken.ts new file mode 100644 index 0000000..a79cf8f --- /dev/null +++ b/libs/middlewares/authWithRefreshToken.ts @@ -0,0 +1,45 @@ +import { NextRequest, NextFetchEvent, NextResponse } from "next/server"; +// import { setCookie } from '../../utils/cookies' +import client from "../client"; +import jwt from "jsonwebtoken" +import 'dotenv/config' + +const secret_key = process.env.SECRET_KEY || ""; + +let userId: string | object | Buffer; + +export const authNoRefreshToken = async ( + req: NextRequest, + ev: NextFetchEvent, +) => { + try { + if(req.cookies.has('refreshToken')){ + const refreshToken = req.cookies.get('refreshToken'); + if(refreshToken !== undefined){ + const identifier = jwt.verify(refreshToken, secret_key); + + if(!identifier){ + throw new Error("토큰이 존재하지 않습니다."); + }; + + const user = await client.user.findUnique({where:{identifier}}); + if(user == null){ + throw new Error("토큰이 유효하지 않습니다. 다시 로그인해 주십시오."); + }; + + if(user?.refreshToken !== refreshToken){ + throw new Error("서버에 저장된 토큰 정보와 일치하지 않습니다. 다시 로그인해 주십시오."); + }; + + const response = NextResponse.next(); + response.cookies.set('accessToken', jwt.sign(userId, secret_key, {expiresIn: '1h'})); // body에 담아주도록 수정 + + return response; + } + }else{ + throw new Error("토큰이 존재하지 않습니다."); + } + } catch (error:any) { + throw new Error(error) + } +} \ No newline at end of file diff --git a/libs/middlewares/isLogin.ts b/libs/middlewares/isLogin.ts new file mode 100644 index 0000000..1956805 --- /dev/null +++ b/libs/middlewares/isLogin.ts @@ -0,0 +1,32 @@ +import { NextRequest, NextFetchEvent, NextResponse } from "next/server"; +import client from "../client"; +import jwt from "jsonwebtoken" +// import cookies from 'next-cookies'; + +import 'dotenv/config' +const secret_key = process.env.SECRET_KEY || ""; + +export function middleware( + req: NextRequest, + ev: NextFetchEvent, + ) { + try { + if(!req.cookies.has('accessToken')){ + return NextResponse.rewrite(new URL('/login', req.url)); + } else { + return new Response( + JSON.stringify({"message": "이미 로그인된 상태입니다."}), + { status: 401 }, + ) + } + } catch (error) { + return new Response( + JSON.stringify({error}), + { status: 400 }, + ) + } + } + + export const config = { + matcher: ['/api/user/login', 'api/user/signup'] + } \ No newline at end of file diff --git a/libs/middlewares/validation.ts b/libs/middlewares/validation.ts new file mode 100644 index 0000000..750debd --- /dev/null +++ b/libs/middlewares/validation.ts @@ -0,0 +1,29 @@ +import { NextRequest, NextFetchEvent, NextResponse } from "next/server"; +import Joi from "joi"; + +export function joiValidation( + req: NextRequest, + ev: NextFetchEvent, + ) { + const emailRegExp = /[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]$/i; + const passwordRegExp = /(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])/i; + const schema = Joi.object().keys({ + email: Joi.string().regex(emailRegExp).email(), + password: Joi.string().regex(passwordRegExp) + }); + try { + schema.validate(req.body) + } catch (error) { + return new Response( + JSON.stringify({error}), + { status: 400 }, + ) + } + + return NextResponse.rewrite(new URL('/home', req.nextUrl)); // 경로 수정 필요 + + } +export const config = { + matcher: ['/api/user/signup'] +} + diff --git a/package-lock.json b/package-lock.json index a915877..7c9f207 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,12 @@ "dependencies": { "@prisma/client": "^4.5.0", "@tanstack/react-query": "^4.14.1", + "joi": "^17.7.0", "jsonwebtoken": "^8.5.1", "next": "13.0.0", + "next-connect": "^0.13.0", + "next-cookies": "^2.0.3", + "next-joi": "^2.2.1", "react": "18.2.0", "react-dom": "18.2.0", "react-hook-form": "^7.38.0" @@ -93,6 +97,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.7", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", @@ -433,6 +450,24 @@ "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==", "dev": true }, + "node_modules/@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", + "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, "node_modules/@swc/helpers": { "version": "0.4.11", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz", @@ -500,6 +535,11 @@ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "dev": true }, + "node_modules/@types/cookie": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz", + "integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==" + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -1176,6 +1216,14 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/core-js-pure": { "version": "3.26.0", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.0.tgz", @@ -2683,6 +2731,18 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/joi": { + "version": "17.7.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.7.0.tgz", + "integrity": "sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==", + "dependencies": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.0.0" + } + }, "node_modules/js-sdsl": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", @@ -3051,6 +3111,31 @@ } } }, + "node_modules/next-connect": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/next-connect/-/next-connect-0.13.0.tgz", + "integrity": "sha512-f2G4edY01XomjCECSrgOpb/zzQinJO6Whd8Zds0+rLUYhj5cLwkh6FVvZsQCSSbxSc4k9nCwNuk5NLIhvO1gUA==", + "dependencies": { + "trouter": "^3.2.0" + } + }, + "node_modules/next-cookies": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/next-cookies/-/next-cookies-2.0.3.tgz", + "integrity": "sha512-YVCQzwZx+sz+KqLO4y9niHH9jjz6jajlEQbAKfsYVT6DOfngb/0k5l6vFK4rmpExVug96pGag8OBsdSRL9FZhQ==", + "dependencies": { + "universal-cookie": "^4.0.2" + } + }, + "node_modules/next-joi": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/next-joi/-/next-joi-2.2.1.tgz", + "integrity": "sha512-m6/rDj9a9sp0CeMGy3np/7T2663QFinfiTY4MuJ9LEicU+6SiDim4wnsqG5CfzI4IQX4tupN6jSCtsv0t2EWnQ==", + "peerDependencies": { + "joi": ">=17.1.1", + "next": ">=9.5.1" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.14", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", @@ -3685,6 +3770,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regexparam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-1.3.0.tgz", + "integrity": "sha512-6IQpFBv6e5vz1QAqI+V4k8P2e/3gRrqfCJ9FI+O1FLQTO+Uz6RXZEZOPmTJ6hlGj7gkERzY5BRCv09whKP96/g==", + "engines": { + "node": ">=6" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -4064,6 +4157,17 @@ "node": ">=8.0" } }, + "node_modules/trouter": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/trouter/-/trouter-3.2.0.tgz", + "integrity": "sha512-rLLXbhTObLy2MBVjLC+jTnoIKw99n0GuJs9ov10J870vDw5qhTurPzsDrudNtBf5w/CZ9ctZy2p2IMmhGcel2w==", + "dependencies": { + "regexparam": "^1.3.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -4212,6 +4316,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/universal-cookie": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.4.tgz", + "integrity": "sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw==", + "dependencies": { + "@types/cookie": "^0.3.3", + "cookie": "^0.4.0" + } + }, "node_modules/update-browserslist-db": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", @@ -4405,6 +4518,19 @@ "strip-json-comments": "^3.1.1" } }, + "@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" + }, + "@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, "@humanwhocodes/config-array": { "version": "0.11.7", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", @@ -4593,6 +4719,24 @@ "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==", "dev": true }, + "@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@sideway/formula": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", + "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" + }, + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, "@swc/helpers": { "version": "0.4.11", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz", @@ -4639,6 +4783,11 @@ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "dev": true }, + "@types/cookie": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz", + "integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==" + }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -5116,6 +5265,11 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + }, "core-js-pure": { "version": "3.26.0", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.0.tgz", @@ -6208,6 +6362,18 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "joi": { + "version": "17.7.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.7.0.tgz", + "integrity": "sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==", + "requires": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.0.0" + } + }, "js-sdsl": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", @@ -6506,6 +6672,28 @@ } } }, + "next-connect": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/next-connect/-/next-connect-0.13.0.tgz", + "integrity": "sha512-f2G4edY01XomjCECSrgOpb/zzQinJO6Whd8Zds0+rLUYhj5cLwkh6FVvZsQCSSbxSc4k9nCwNuk5NLIhvO1gUA==", + "requires": { + "trouter": "^3.2.0" + } + }, + "next-cookies": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/next-cookies/-/next-cookies-2.0.3.tgz", + "integrity": "sha512-YVCQzwZx+sz+KqLO4y9niHH9jjz6jajlEQbAKfsYVT6DOfngb/0k5l6vFK4rmpExVug96pGag8OBsdSRL9FZhQ==", + "requires": { + "universal-cookie": "^4.0.2" + } + }, + "next-joi": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/next-joi/-/next-joi-2.2.1.tgz", + "integrity": "sha512-m6/rDj9a9sp0CeMGy3np/7T2663QFinfiTY4MuJ9LEicU+6SiDim4wnsqG5CfzI4IQX4tupN6jSCtsv0t2EWnQ==", + "requires": {} + }, "node-releases": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", @@ -6908,6 +7096,11 @@ "functions-have-names": "^1.2.2" } }, + "regexparam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-1.3.0.tgz", + "integrity": "sha512-6IQpFBv6e5vz1QAqI+V4k8P2e/3gRrqfCJ9FI+O1FLQTO+Uz6RXZEZOPmTJ6hlGj7gkERzY5BRCv09whKP96/g==" + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -7153,6 +7346,14 @@ "is-number": "^7.0.0" } }, + "trouter": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/trouter/-/trouter-3.2.0.tgz", + "integrity": "sha512-rLLXbhTObLy2MBVjLC+jTnoIKw99n0GuJs9ov10J870vDw5qhTurPzsDrudNtBf5w/CZ9ctZy2p2IMmhGcel2w==", + "requires": { + "regexparam": "^1.3.0" + } + }, "ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -7255,6 +7456,15 @@ "which-boxed-primitive": "^1.0.2" } }, + "universal-cookie": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.4.tgz", + "integrity": "sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw==", + "requires": { + "@types/cookie": "^0.3.3", + "cookie": "^0.4.0" + } + }, "update-browserslist-db": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", diff --git a/package.json b/package.json index 74b7963..dc620bc 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,12 @@ "dependencies": { "@prisma/client": "^4.5.0", "@tanstack/react-query": "^4.14.1", + "joi": "^17.7.0", "jsonwebtoken": "^8.5.1", "next": "13.0.0", + "next-connect": "^0.13.0", + "next-cookies": "^2.0.3", + "next-joi": "^2.2.1", "react": "18.2.0", "react-dom": "18.2.0", "react-hook-form": "^7.38.0" diff --git a/pages/api/login.ts b/pages/api/login.ts deleted file mode 100644 index b02b65d..0000000 --- a/pages/api/login.ts +++ /dev/null @@ -1,47 +0,0 @@ -// Next.js API route support: https://nextjs.org/docs/api-routes/introduction -import type { NextApiRequest, NextApiResponse } from "next"; -import client from "../../libs/client"; - -// 크롤링 -/* import axios from 'axios'; -const cheerio = require('cheerio'); */ - -export default async function handler( - req: NextApiRequest, - res: NextApiResponse -) { - const { email, password, nickname } = req.body; - try { - const findOneUser = await client.user.findUnique({ - where: { - email: email, - }, - }); - console.log(findOneUser); - - const result = await client.user.create({ - data: { - email: email + "qw", - identifier: "testtest", - password: password, - nickname: nickname + "qw", - profileImg: "../test", - }, - }); - - res.status(200).send("후잉"); - } catch (error) { - console.log(error); - res.status(200).send({ result: "실패" }); - } -} - -// userId Int @id @default(autoincrement()) -// email String @unique -// identifier String -// nickname String @unique -// password String -// profileImg String ? -// refreshToken String ? -// createdAt DateTime @default(now()) -// updatedAt DateTime @updatedAt diff --git a/pages/api/middlewares/_authNoRefreshToken.ts b/pages/api/middlewares/_authNoRefreshToken.ts deleted file mode 100644 index c4f48cd..0000000 --- a/pages/api/middlewares/_authNoRefreshToken.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; -// import { setCookie } from '../../utils/cookies' -import client from "../../../libs/client"; -import jwt from "jsonwebtoken" -import 'dotenv/config' - -const secret_key = process.env.SECRET_KEY || ""; -export const authNoRefreshToken = async ( - req: NextApiRequest, - res: NextApiResponse, -) => { - if(req.cookies.accessToken){ - const accessToken = req.cookies.accessToken; - // let userId: string | jwt.JwtPayload | undefined; - - jwt.verify(accessToken, secret_key, (err, decoded) => { - if(err){ - res.status(400).json({"message": "accessToken이 유효하지 않습니다.", errorMessage: err}) - }; - // The if (res.locals) in itself is problematic, because res.locals is an Express convention. - // This condition may be always false if you use another Node framework. - // userId = decoded; - }) - }else{ - res.status(400).json({"message": "로그인이 필요합니다."}); - } - -} \ No newline at end of file diff --git a/pages/api/middlewares/authWithRefreshToken.ts b/pages/api/middlewares/authWithRefreshToken.ts deleted file mode 100644 index f30756d..0000000 --- a/pages/api/middlewares/authWithRefreshToken.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; -import { setCookie } from '../../utils/cookies' -import client from "../../../libs/client"; -import jwt from "jsonwebtoken" -import 'dotenv/config' - -const secret_key = process.env.SECRET_KEY || ""; -let userId: string | object | Buffer; - -export const authNoRefreshToken = async ( - req: NextApiRequest, - res: NextApiResponse, -) => { - if(req.cookies.refreshToken){ - const refreshToken = req.cookies.refreshToken; - const identifier = jwt.verify(refreshToken, secret_key); - if(!identifier){ - res.status(400).json({"message": "토큰이 존재하지 않습니다. "}) - } - - const user = await client.user.findUnique({where:{identifier}}); - - if(user == null){ - res.status(400).json({"message": "토큰이 유효하지 않습니다. 다시 로그인해 주십시오."}) - }; - - if(user?.refreshToken !== refreshToken){ - res.status(400).json({"message": "서버에 저장된 토큰 정보와 일치하지 않습니다. 다시 로그인해 주십시오."}) - } - // The if (res.locals) in itself is problematic, because res.locals is an Express convention. - // This condition may be always false if you use another Node framework. - - setCookie(res, 'accessToken', jwt.sign(userId, secret_key, {expiresIn: '1h'})) - res.getHeader('Set-Cookie') - - }else{ - res.status(400).json({"message": "로그인이 필요합니다."}); - } -} \ No newline at end of file diff --git a/pages/api/user/_isLogin.ts b/pages/api/user/_isLogin.ts deleted file mode 100644 index 4dc2a7b..0000000 --- a/pages/api/user/_isLogin.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { NextApiRequest, NextApiResponse } from "next"; -import { NextResponse } from "next/server"; -import client from "../../../libs/client"; -import jwt from "jsonwebtoken" -import 'dotenv/config' -const secret_key = process.env.SECRET_KEY || ""; - -export const isLogin = async ( - req: NextApiRequest, - res: NextApiResponse, - ) => { - const accessToken = req.cookies.accessToken; - if(accessToken){ - jwt.verify(accessToken, secret_key, (err, decoded) => { - if(err){ - res.status(400).send(false); - } - res.status(200).send(true); - }); - } - } - - export const isLogout = async ( - req: NextApiRequest, - res: NextApiResponse, - ) => { - const accessToken = req.cookies.accessToken; - if(accessToken){ - jwt.verify(accessToken, secret_key, (err, decoded) => { - if(err){ - res.status(200).send(true); - } - - res.status(400).send(false); - }); - } - } diff --git a/pages/api/user/login.ts b/pages/api/user/login.ts index 5528f70..b7861f5 100644 --- a/pages/api/user/login.ts +++ b/pages/api/user/login.ts @@ -2,7 +2,8 @@ import type { NextApiRequest, NextApiResponse } from "next"; import client from "../../../libs/client"; import jwt from "jsonwebtoken"; -import 'dotenv/config' +import 'dotenv/config'; +import { join } from "path"; const secret_key = process.env.SECRET_KEY || "" interface reqBody { email: string | undefined @@ -13,7 +14,7 @@ export default async function handler( req: NextApiRequest, res: NextApiResponse ) { - const { email, password }:reqBody = req.body; + const { email, password }: reqBody = req.body; try { if(!email||!password){ @@ -21,39 +22,30 @@ export default async function handler( } const user = await client.user.findUnique({where:{email}}); - const identifier = user?.identifier + const userId = user?.userId /**accessToken 발급 */ - if(identifier == undefined){ + if(userId == undefined){ res.status(400).send("유저 정보가 없습니다."); }; const accessToken = jwt.sign( - {identifier}, + {userId}, secret_key, { expiresIn: '1h' } ); /**refreshToken 발급 */ const refreshToken = jwt.sign( - {identifier}, + {userId}, secret_key, { expiresIn: '7d' } ); - await client.user.update({where:{identifier},data:{refreshToken}}); + await client.user.update({where:{userId},data:{refreshToken}}); res.status(200).json({accessToken,refreshToken}) } catch (error) { - res.status(400).json({ error, result: "실패" }); + res.status(400).json({ error, result: "로그인에 실패하였습니다." }); } } -// userId Int @id @default(autoincrement()) -// email String @unique -// identifier String -// nickname String @unique -// password String -// profileImg String ? -// refreshToken String ? -// createdAt DateTime @default(now()) -// updatedAt DateTime @updatedAt diff --git a/pages/api/user/signup.ts b/pages/api/user/signup.ts index e8041fe..d3ec27a 100644 --- a/pages/api/user/signup.ts +++ b/pages/api/user/signup.ts @@ -1,40 +1,35 @@ import type { NextApiRequest, NextApiResponse } from "next"; import client from "../../../libs/client"; - - -function makeid(length:number) { - var result = ''; - var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - var charactersLength = characters.length; - for ( var i = 0; i < length; i++ ) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)); - } - return result; -} +"; export default async function handler( req: NextApiRequest, res: NextApiResponse ) { - const {email,nickname,password,confirmPassword}=req.body; - const user = await client.user.findUnique({ - where:{email} - }) - if(password!==confirmPassword){ - res.status(400).send("비밀번호를 다시 확인 해주세요.") - } - if(user){ - res.status(400).send("중복된 이메일 입니다.") - } - await client.user.create({ - data:{ - email, - nickname, - password, - identifier:makeid(7) + const {email, password, size}=req.body; + + try { + const user = await client.user.findUnique({ + where:{email} + }) + + if(user){ + res.status(400).send("중복된 이메일 입니다.") } - }) + - res.status(200).send("회원가입이 완료 되었습니다.") -} \ No newline at end of file + const nickname = email.split("@")[0] + await client.user.create({ + data:{ + email, + nickname, + size, + password + } + }) + res.status(200).send("회원가입이 완료 되었습니다.") + } catch (error) { + res.status(400).json(error) + } +} diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 6fe40b7..f406b64 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -19,11 +19,11 @@ datasource db { model User { userId Int @id @default(autoincrement()) email String @unique - identifier String @unique nickname String @unique password String profileImg String ? refreshToken String ? + size Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt comment Comment[] @@ -32,7 +32,6 @@ model User { model Product { productId Int @id @default(autoincrement()) - identifier String @unique name String price Int koeanDesc String? @@ -49,27 +48,25 @@ model Product { model Style { styleId Int @id @default(autoincrement()) - identifier String @unique profileImg String styleImg String hashtag String like Int content String - user User @relation(fields: [userId], references: [identifier],onDelete: Cascade) - userId String + user User @relation(fields: [userId], references: [userId],onDelete: Cascade) + userId Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt comment Comment[] } model Comment { - commentId Int @id @default(autoincrement()) - identifier String @unique + commentId Int @id @default(autoincrement()) comment String - user User @relation(fields: [userId], references: [identifier],onDelete: Cascade) - userId String - style Style @relation(fields: [styleId], references: [identifier],onDelete: Cascade) - styleId String + user User @relation(fields: [userId], references: [userId], onDelete: Cascade) + userId Int + style Style @relation(fields: [styleId], references: [styleId], onDelete: Cascade) + styleId Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } \ No newline at end of file From 98f06edd248f490228f3b83d63a0748d9ac27854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8E=E1=85=AC=E1=84=8C=E1=85=AE=E1=86=AB=E1=84=8B?= =?UTF-8?q?=E1=85=A7=E1=86=BC?= Date: Wed, 2 Nov 2022 22:45:39 +0900 Subject: [PATCH 2/4] =?UTF-8?q?login=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/middlewares/authMiddleware.ts | 3 +- libs/middlewares/isLogin.ts | 2 +- package-lock.json | 340 ++++++++++++++++++++++++++++- package.json | 6 +- pages/api/user/login.ts | 25 ++- pages/api/user/signup.ts | 7 +- 6 files changed, 360 insertions(+), 23 deletions(-) diff --git a/libs/middlewares/authMiddleware.ts b/libs/middlewares/authMiddleware.ts index 74f287e..4271e1b 100644 --- a/libs/middlewares/authMiddleware.ts +++ b/libs/middlewares/authMiddleware.ts @@ -1,5 +1,4 @@ import { NextRequest, NextFetchEvent, NextResponse } from "next/server"; -import client from "../client"; import jwt from "jsonwebtoken" import 'dotenv/config' @@ -34,4 +33,6 @@ export async function middleware( { status: 401 }, ); } + + } diff --git a/libs/middlewares/isLogin.ts b/libs/middlewares/isLogin.ts index 1956805..16f58f9 100644 --- a/libs/middlewares/isLogin.ts +++ b/libs/middlewares/isLogin.ts @@ -28,5 +28,5 @@ export function middleware( } export const config = { - matcher: ['/api/user/login', 'api/user/signup'] + matcher: ['/api/user/login', '/api/user/signup'] } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 7c9f207..6f3fb97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,8 @@ "dependencies": { "@prisma/client": "^4.5.0", "@tanstack/react-query": "^4.14.1", + "@types/sanitize-html": "^2.6.2", + "bcryptjs": "^2.4.3", "joi": "^17.7.0", "jsonwebtoken": "^8.5.1", "next": "13.0.0", @@ -18,9 +20,11 @@ "next-joi": "^2.2.1", "react": "18.2.0", "react-dom": "18.2.0", - "react-hook-form": "^7.38.0" + "react-hook-form": "^7.38.0", + "sanitize-html": "^2.7.3" }, "devDependencies": { + "@types/bcryptjs": "^2.4.2", "@types/jsonwebtoken": "^8.5.9", "@types/node": "^18.11.8", "@types/react": "18.0.24", @@ -535,6 +539,12 @@ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "dev": true }, + "node_modules/@types/bcryptjs": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", + "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==", + "dev": true + }, "node_modules/@types/cookie": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz", @@ -587,6 +597,80 @@ "@types/react": "*" } }, + "node_modules/@types/sanitize-html": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.6.2.tgz", + "integrity": "sha512-7Lu2zMQnmHHQGKXVvCOhSziQMpa+R2hMHFefzbYoYMHeaXR0uXqNeOc3JeQQQ8/6Xa2Br/P1IQTLzV09xxAiUQ==", + "dependencies": { + "htmlparser2": "^6.0.0" + } + }, + "node_modules/@types/sanitize-html/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/@types/sanitize-html/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/@types/sanitize-html/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/@types/sanitize-html/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@types/sanitize-html/node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, "node_modules/@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", @@ -966,6 +1050,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -1330,6 +1419,14 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/define-properties": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", @@ -1444,7 +1541,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, "funding": [ { "type": "github", @@ -1590,7 +1686,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "engines": { "node": ">=10" }, @@ -2655,6 +2750,14 @@ "node": ">=8" } }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -3378,6 +3481,11 @@ "node": ">=6" } }, + "node_modules/parse-srcset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", + "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" + }, "node_modules/parse5": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz", @@ -3475,7 +3583,6 @@ "version": "8.4.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -3897,6 +4004,85 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sanitize-html": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.7.3.tgz", + "integrity": "sha512-jMaHG29ak4miiJ8wgqA1849iInqORgNv7SLfSw9LtfOhEUQ1C0YHKH73R+hgyufBW9ZFeJrb057k9hjlfBCVlw==", + "dependencies": { + "deepmerge": "^4.2.2", + "escape-string-regexp": "^4.0.0", + "htmlparser2": "^6.0.0", + "is-plain-object": "^5.0.0", + "parse-srcset": "^1.0.2", + "postcss": "^8.3.11" + } + }, + "node_modules/sanitize-html/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/sanitize-html/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/sanitize-html/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/sanitize-html/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/sanitize-html/node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, "node_modules/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", @@ -4783,6 +4969,12 @@ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "dev": true }, + "@types/bcryptjs": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", + "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==", + "dev": true + }, "@types/cookie": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz", @@ -4835,6 +5027,60 @@ "@types/react": "*" } }, + "@types/sanitize-html": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.6.2.tgz", + "integrity": "sha512-7Lu2zMQnmHHQGKXVvCOhSziQMpa+R2hMHFefzbYoYMHeaXR0uXqNeOc3JeQQQ8/6Xa2Br/P1IQTLzV09xxAiUQ==", + "requires": { + "htmlparser2": "^6.0.0" + }, + "dependencies": { + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + } + } + }, "@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", @@ -5089,6 +5335,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -5345,6 +5596,11 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + }, "define-properties": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", @@ -5428,8 +5684,7 @@ "domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" }, "domhandler": { "version": "5.0.3", @@ -5538,8 +5793,7 @@ "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, "eslint": { "version": "8.26.0", @@ -6310,6 +6564,11 @@ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -6850,6 +7109,11 @@ "callsites": "^3.0.0" } }, + "parse-srcset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", + "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" + }, "parse5": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz", @@ -6920,7 +7184,6 @@ "version": "8.4.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", - "dev": true, "requires": { "nanoid": "^3.3.4", "picocolors": "^1.0.0", @@ -7164,6 +7427,65 @@ "is-regex": "^1.1.4" } }, + "sanitize-html": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.7.3.tgz", + "integrity": "sha512-jMaHG29ak4miiJ8wgqA1849iInqORgNv7SLfSw9LtfOhEUQ1C0YHKH73R+hgyufBW9ZFeJrb057k9hjlfBCVlw==", + "requires": { + "deepmerge": "^4.2.2", + "escape-string-regexp": "^4.0.0", + "htmlparser2": "^6.0.0", + "is-plain-object": "^5.0.0", + "parse-srcset": "^1.0.2", + "postcss": "^8.3.11" + }, + "dependencies": { + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + } + } + }, "scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", diff --git a/package.json b/package.json index dc620bc..1f9d2a7 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,8 @@ "dependencies": { "@prisma/client": "^4.5.0", "@tanstack/react-query": "^4.14.1", + "@types/sanitize-html": "^2.6.2", + "bcryptjs": "^2.4.3", "joi": "^17.7.0", "jsonwebtoken": "^8.5.1", "next": "13.0.0", @@ -19,9 +21,11 @@ "next-joi": "^2.2.1", "react": "18.2.0", "react-dom": "18.2.0", - "react-hook-form": "^7.38.0" + "react-hook-form": "^7.38.0", + "sanitize-html": "^2.7.3" }, "devDependencies": { + "@types/bcryptjs": "^2.4.2", "@types/jsonwebtoken": "^8.5.9", "@types/node": "^18.11.8", "@types/react": "18.0.24", diff --git a/pages/api/user/login.ts b/pages/api/user/login.ts index b7861f5..617b516 100644 --- a/pages/api/user/login.ts +++ b/pages/api/user/login.ts @@ -3,7 +3,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; import client from "../../../libs/client"; import jwt from "jsonwebtoken"; import 'dotenv/config'; -import { join } from "path"; +import bcrypt from "bcryptjs" const secret_key = process.env.SECRET_KEY || "" interface reqBody { email: string | undefined @@ -15,26 +15,35 @@ export default async function handler( res: NextApiResponse ) { const { email, password }: reqBody = req.body; - + try { if(!email||!password){ throw new Error("아이디 혹은 비밀번호를 입력해 주세요") } const user = await client.user.findUnique({where:{email}}); - const userId = user?.userId - /**accessToken 발급 */ + const userId = user?.userId; + const encPass = user?.password; + if(userId == undefined){ - res.status(400).send("유저 정보가 없습니다."); + res.status(400).send("이메일 또는 패스워드가 일치하지 않습니다."); }; + if(encPass !== undefined){ + const re = await bcrypt.compare(encPass, password); + if(!re){ + res.status(400).send("이메일 또는 패스워드가 일치하지 않습니다."); + } + }else { + res.status(400).send("존재하지 않는 유저입니다."); + } + const accessToken = jwt.sign( {userId}, secret_key, { expiresIn: '1h' } ); - /**refreshToken 발급 */ const refreshToken = jwt.sign( {userId}, secret_key, @@ -43,7 +52,9 @@ export default async function handler( await client.user.update({where:{userId},data:{refreshToken}}); - res.status(200).json({accessToken,refreshToken}) + res.setHeader('Set-Cookie', `accessToken: ${accessToken}`); + res.status(200).json({refreshToken}); + } catch (error) { res.status(400).json({ error, result: "로그인에 실패하였습니다." }); } diff --git a/pages/api/user/signup.ts b/pages/api/user/signup.ts index d3ec27a..caef170 100644 --- a/pages/api/user/signup.ts +++ b/pages/api/user/signup.ts @@ -1,7 +1,6 @@ import type { NextApiRequest, NextApiResponse } from "next"; import client from "../../../libs/client"; -"; - +import bcrypt from 'bcryptjs' export default async function handler( req: NextApiRequest, @@ -18,14 +17,14 @@ export default async function handler( res.status(400).send("중복된 이메일 입니다.") } - + const encPass = await bcrypt.hash(password, 10); const nickname = email.split("@")[0] await client.user.create({ data:{ email, nickname, size, - password + password: encPass } }) res.status(200).send("회원가입이 완료 되었습니다.") From c907e5d29483348a3bc5421e6b6e479947e2065a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8E=E1=85=AC=E1=84=8C=E1=85=AE=E1=86=AB=E1=84=8B?= =?UTF-8?q?=E1=85=A7=E1=86=BC?= Date: Wed, 2 Nov 2022 23:30:01 +0900 Subject: [PATCH 3/4] =?UTF-8?q?model=20product=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- prisma/schema.prisma | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index f406b64..6574237 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -31,19 +31,15 @@ model User { } model Product { - productId Int @id @default(autoincrement()) - name String + productId Int @id @default(autoincrement()) price Int - koeanDesc String? - size Int? - releasedDate DateTime? @default(now()) - color String? - likeNumber Int? @default(0) + nameEng String brand String - category String? - gender String? + nameKr String + quickdlivery Boolean + imgUrl String @db.VarChar(500) + pid String createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt } model Style { From eaea4d830afd72afb77754af9021993c47b06060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8E=E1=85=AC=E1=84=8C=E1=85=AE=E1=86=AB=E1=84=8B?= =?UTF-8?q?=E1=85=A7=E1=86=BC?= Date: Wed, 2 Nov 2022 23:39:08 +0900 Subject: [PATCH 4/4] model user nickname to optional --- prisma/schema.prisma | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 6574237..3577639 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -19,10 +19,9 @@ datasource db { model User { userId Int @id @default(autoincrement()) email String @unique - nickname String @unique + nickname String? @unique password String - profileImg String ? - refreshToken String ? + refreshToken String? size Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt