From 724ba2b262bad7764ecbf605a3369c588b567352 Mon Sep 17 00:00:00 2001 From: jeongmin Date: Mon, 4 Dec 2023 15:40:04 +0900 Subject: [PATCH 1/8] =?UTF-8?q?refactor:=20strategy=20=ED=8F=B4=EB=8D=94?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/src/auth/{ => strategies}/jwt.strategy.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename BE/src/auth/{ => strategies}/jwt.strategy.ts (100%) diff --git a/BE/src/auth/jwt.strategy.ts b/BE/src/auth/strategies/jwt.strategy.ts similarity index 100% rename from BE/src/auth/jwt.strategy.ts rename to BE/src/auth/strategies/jwt.strategy.ts From a2d5df355c52a0c3814e4da6c99d7f64faa4a0a0 Mon Sep 17 00:00:00 2001 From: jeongmin Date: Mon, 4 Dec 2023 15:41:09 +0900 Subject: [PATCH 2/8] =?UTF-8?q?feat:=20passport-kakao=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=20=EC=84=A4=EC=B9=98=20=EB=B0=8F=20profile=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/package-lock.json | 41 ++++++++++++++++++++++++ BE/package.json | 1 + BE/src/auth/auth.controller.ts | 9 +++++- BE/src/auth/auth.module.ts | 4 ++- BE/src/auth/strategies/kakao.strategy.ts | 35 ++++++++++++++++++++ 5 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 BE/src/auth/strategies/kakao.strategy.ts diff --git a/BE/package-lock.json b/BE/package-lock.json index 23c7f7e..d23c4d3 100644 --- a/BE/package-lock.json +++ b/BE/package-lock.json @@ -31,6 +31,7 @@ "mysql2": "^3.6.3", "passport": "^0.6.0", "passport-jwt": "^4.0.1", + "passport-kakao": "^1.0.1", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", "typeorm": "^0.3.17" @@ -7211,6 +7212,11 @@ "node": ">=8" } }, + "node_modules/oauth": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", + "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -7465,6 +7471,28 @@ "passport-strategy": "^1.0.0" } }, + "node_modules/passport-kakao": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/passport-kakao/-/passport-kakao-1.0.1.tgz", + "integrity": "sha512-uItaYRVrTHL6iGPMnMZvPa/O1GrAdh/V6EMjOHcFlQcVroZ9wgG7BZ5PonMNJCxfHQ3L2QVNRnzhKWUzSsumbw==", + "dependencies": { + "passport-oauth2": "~1.1.2", + "pkginfo": "~0.3.0" + } + }, + "node_modules/passport-oauth2": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.1.2.tgz", + "integrity": "sha512-wpsGtJDHHQUjyc9WcV9FFB0bphFExpmKtzkQrxpH1vnSr6RcWa3ZEGHx/zGKAh2PN7Po9TKYB1fJeOiIBspNPA==", + "dependencies": { + "oauth": "0.9.x", + "passport-strategy": "1.x.x", + "uid2": "0.0.x" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/passport-strategy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", @@ -7641,6 +7669,14 @@ "node": ">=8" } }, + "node_modules/pkginfo": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", + "integrity": "sha512-yO5feByMzAp96LtP58wvPKSbaKAi/1C4kV9XpTctr6EepnP6F33RBNOiVrdz9BrPA98U2BMFsTNHo44TWcbQ2A==", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", @@ -9408,6 +9444,11 @@ "node": ">=8" } }, + "node_modules/uid2": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.4.tgz", + "integrity": "sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==" + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", diff --git a/BE/package.json b/BE/package.json index 4c40eb7..cf0642c 100644 --- a/BE/package.json +++ b/BE/package.json @@ -43,6 +43,7 @@ "mysql2": "^3.6.3", "passport": "^0.6.0", "passport-jwt": "^4.0.1", + "passport-kakao": "^1.0.1", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", "typeorm": "^0.3.17" diff --git a/BE/src/auth/auth.controller.ts b/BE/src/auth/auth.controller.ts index 7aa0041..257087d 100644 --- a/BE/src/auth/auth.controller.ts +++ b/BE/src/auth/auth.controller.ts @@ -1,6 +1,7 @@ import { Body, Controller, + Get, HttpCode, Post, Req, @@ -16,13 +17,19 @@ import { import { CreateUserDto } from "./dto/users.dto"; import { User } from "./users.entity"; import { GetUser } from "./get-user.decorator"; -import { JwtAuthGuard } from "./guard/auth.jwt-guard"; import { Request } from "express"; +import { AuthGuard } from "@nestjs/passport"; @Controller("auth") export class AuthController { constructor(private authService: AuthService) {} + @Get("/kakao/callback") + @UseGuards(AuthGuard("kakao")) + kakaoSignIn(@GetUser() user) { + console.log(user); + } + @Post("/signup") @HttpCode(204) async signUp(@Body() createUserDto: CreateUserDto): Promise { diff --git a/BE/src/auth/auth.module.ts b/BE/src/auth/auth.module.ts index a0a5d54..9e2f99d 100644 --- a/BE/src/auth/auth.module.ts +++ b/BE/src/auth/auth.module.ts @@ -4,12 +4,13 @@ import { AuthController } from "./auth.controller"; import { AuthService } from "./auth.service"; import { JwtModule } from "@nestjs/jwt"; import { PassportModule } from "@nestjs/passport"; -import { JwtStrategy } from "./jwt.strategy"; +import { JwtStrategy } from "./strategies/jwt.strategy"; import { PrivateDiaryGuard } from "./guard/auth.diary-guard"; import { TypeOrmModule } from "@nestjs/typeorm"; import { User } from "./users.entity"; import { UsersRepository } from "./users.repository"; import { DiariesRepository } from "src/diaries/diaries.repository"; +import { KakaoStrategy } from "./strategies/kakao.strategy"; @Module({ imports: [ @@ -26,6 +27,7 @@ import { DiariesRepository } from "src/diaries/diaries.repository"; providers: [ AuthService, JwtStrategy, + KakaoStrategy, UsersRepository, PrivateDiaryGuard, DiariesRepository, diff --git a/BE/src/auth/strategies/kakao.strategy.ts b/BE/src/auth/strategies/kakao.strategy.ts new file mode 100644 index 0000000..45d4e68 --- /dev/null +++ b/BE/src/auth/strategies/kakao.strategy.ts @@ -0,0 +1,35 @@ +import "dotenv/config"; +import { Injectable } from "@nestjs/common"; +import { PassportStrategy } from "@nestjs/passport"; +import { Profile, Strategy } from "passport-kakao"; + +@Injectable() +export class KakaoStrategy extends PassportStrategy(Strategy) { + constructor() { + super({ + clientID: process.env.KAKAO_CLIENT_ID, + clientSecret: "", + callbackURL: `${process.env.BACKEND_URL}/auth/kakao/callback`, + }); + } + + async validate( + accessToken: string, + refreshToken: string, + profile: Profile, + done: (error: any, user?: any, info?: any) => void, + ) { + try { + const { _json } = profile; + console.log(_json); + const user = { + kakaoId: _json.id, + nickname: _json.properties.nickname, + email: _json.kakao_account.email, + }; + done(null, user); + } catch (error) { + done(error); + } + } +} From 2c8585f8fb0dd4a4adbc671ed44f3c8b2db01635 Mon Sep 17 00:00:00 2001 From: jeongmin Date: Tue, 5 Dec 2023 11:33:10 +0900 Subject: [PATCH 3/8] =?UTF-8?q?feat:=20kakao=20login=20API=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=EB=AA=A8=EB=93=88=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/src/auth/auth.controller.ts | 8 +++- BE/src/auth/auth.service.ts | 68 +++++++++++++--------------------- 2 files changed, 32 insertions(+), 44 deletions(-) diff --git a/BE/src/auth/auth.controller.ts b/BE/src/auth/auth.controller.ts index e86c738..a32084a 100644 --- a/BE/src/auth/auth.controller.ts +++ b/BE/src/auth/auth.controller.ts @@ -26,8 +26,12 @@ export class AuthController { @Get("/kakao/callback") @UseGuards(AuthGuard("kakao")) - kakaoSignIn(@GetUser() user) { - console.log(user); + @HttpCode(201) + async kakaoSignIn( + @GetUser() user: User, + @Req() request: Request, + ): Promise { + return await this.authService.kakaoSignIn(user, request); } @Get("/naver/callback") diff --git a/BE/src/auth/auth.service.ts b/BE/src/auth/auth.service.ts index c13c127..8691cfa 100644 --- a/BE/src/auth/auth.service.ts +++ b/BE/src/auth/auth.service.ts @@ -33,27 +33,11 @@ export class AuthService { throw new NotFoundException("존재하지 않는 아이디입니다."); } - if (await bcrypt.compare(password, user.password)) { - const accessTokenPayload = { userId }; - const accessToken = await this.jwtService.sign(accessTokenPayload, { - expiresIn: "1h", - }); - - const refreshTokenPayload = { - requestIp: request.ip, - accessToken: accessToken, - }; - const refreshToken = await this.jwtService.sign(refreshTokenPayload, { - expiresIn: "24h", - }); - - // 86000s = 24h - await this.redisClient.set(userId, refreshToken, "EX", 86400); - - return new AccessTokenDto(accessToken); - } else { + if (!(await bcrypt.compare(password, user.password))) { throw new NotFoundException("올바르지 않은 비밀번호입니다."); } + + return this.createUserTokens(userId, request.ip); } async signOut(user: User): Promise { @@ -69,43 +53,43 @@ export class AuthService { const expiredResult = JSON.parse(payload.toString()); const userId = expiredResult.userId; - const accessTokenPayload = { userId }; - const accessToken = await this.jwtService.sign(accessTokenPayload, { - expiresIn: "1h", - }); + return this.createUserTokens(userId, request.ip); + } - const refreshTokenPayload = { - requestIp: request.ip, - accessToken: accessToken, - }; - const refreshToken = await this.jwtService.sign(refreshTokenPayload, { - expiresIn: "24h", - }); + async naverSignIn(user: User, request: Request): Promise { + const userId = user.userId; + const provider = providerEnum.NAVER; - // 86000s = 24h - await this.redisClient.set(userId, refreshToken, "EX", 86400); + if (!(await User.findOne({ where: { userId, provider } }))) { + await user.save(); + } - return new AccessTokenDto(accessToken); + return this.createUserTokens(userId, request.ip); } - async naverSignIn(user: User, request: Request): Promise { - if ( - !(await User.findOne({ - where: { userId: user.userId, provider: providerEnum.NAVER }, - })) - ) { + async kakaoSignIn(user: User, request: Request): Promise { + const userId = user.userId; + const provider = providerEnum.KAKAO; + + if (!(await User.findOne({ where: { userId, provider } }))) { await user.save(); } - const userId = user.userId; + return this.createUserTokens(userId, request.ip); + } + + private async createUserTokens( + userId: string, + requestIp: string, + ): Promise { const accessTokenPayload = { userId }; const accessToken = await this.jwtService.sign(accessTokenPayload, { expiresIn: "1h", }); const refreshTokenPayload = { - requestIp: request.ip, - accessToken: accessToken, + requestIp, + accessToken, }; const refreshToken = await this.jwtService.sign(refreshTokenPayload, { expiresIn: "24h", From dc65c76bfa4a3780659548f141f01d7bd13282d1 Mon Sep 17 00:00:00 2001 From: jeongmin Date: Tue, 5 Dec 2023 11:37:02 +0900 Subject: [PATCH 4/8] =?UTF-8?q?refactor:=20=EB=AF=B8=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EB=B0=8F=20?= =?UTF-8?q?=EC=A4=91=EB=B3=B5=20=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/src/auth/users.repository.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/BE/src/auth/users.repository.ts b/BE/src/auth/users.repository.ts index e77c642..2482edb 100644 --- a/BE/src/auth/users.repository.ts +++ b/BE/src/auth/users.repository.ts @@ -1,7 +1,6 @@ import { ConflictException, InternalServerErrorException, - NotFoundException, } from "@nestjs/common"; import { CreateUserDto } from "./dto/users.dto"; import { User } from "./users.entity"; @@ -34,11 +33,7 @@ export class UsersRepository { try { await user.save(); } catch (error) { - if (error.code === "ER_DUP_ENTRY") { - throw new ConflictException("Existing userId"); - } else { - throw new InternalServerErrorException(); - } + throw new InternalServerErrorException(error); } return user; From 7c18641bd7e94642ddc42cca07ef97f62c26b340 Mon Sep 17 00:00:00 2001 From: jeongmin Date: Tue, 5 Dec 2023 11:56:36 +0900 Subject: [PATCH 5/8] =?UTF-8?q?feat:=20kakaoStrategy=20DB=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=20=EB=B0=8F=20=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EC=95=94=ED=98=B8=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/src/auth/strategies/kakao.strategy.ts | 33 +++++++++++++++++------- BE/src/auth/strategies/naver.strategy.ts | 7 ++++- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/BE/src/auth/strategies/kakao.strategy.ts b/BE/src/auth/strategies/kakao.strategy.ts index 45d4e68..d427e8a 100644 --- a/BE/src/auth/strategies/kakao.strategy.ts +++ b/BE/src/auth/strategies/kakao.strategy.ts @@ -1,14 +1,17 @@ import "dotenv/config"; -import { Injectable } from "@nestjs/common"; +import { BadRequestException, Injectable } from "@nestjs/common"; import { PassportStrategy } from "@nestjs/passport"; import { Profile, Strategy } from "passport-kakao"; +import { providerEnum } from "src/utils/enum"; +import { User } from "../users.entity"; +import * as bcrypt from "bcryptjs"; @Injectable() export class KakaoStrategy extends PassportStrategy(Strategy) { constructor() { super({ clientID: process.env.KAKAO_CLIENT_ID, - clientSecret: "", + clientSecret: process.env.KAKAO_CLIENT_SECRET, callbackURL: `${process.env.BACKEND_URL}/auth/kakao/callback`, }); } @@ -21,15 +24,27 @@ export class KakaoStrategy extends PassportStrategy(Strategy) { ) { try { const { _json } = profile; - console.log(_json); - const user = { - kakaoId: _json.id, - nickname: _json.properties.nickname, - email: _json.kakao_account.email, - }; + const { id, kakao_account, properties } = _json; + + const user = new User(); + + const salt = await bcrypt.genSalt(); + const hashedPassword = await bcrypt.hash(id.toString(), salt); + + user.email = kakao_account.email; + user.userId = id.toString() + "*kakao"; + user.nickname = properties.nickname; + user.password = hashedPassword; + user.provider = providerEnum.KAKAO; + done(null, user); } catch (error) { - done(error); + console.log(error); + done( + new BadRequestException( + `카카오 로그인 중 오류가 발생했습니다 : ${error.message}`, + ), + ); } } } diff --git a/BE/src/auth/strategies/naver.strategy.ts b/BE/src/auth/strategies/naver.strategy.ts index d9d83d9..f7a20ff 100644 --- a/BE/src/auth/strategies/naver.strategy.ts +++ b/BE/src/auth/strategies/naver.strategy.ts @@ -1,8 +1,10 @@ +import "dotenv/config"; import { Injectable, BadRequestException } from "@nestjs/common"; import { PassportStrategy } from "@nestjs/passport"; import { Profile, Strategy } from "passport-naver"; import { User } from "../users.entity"; import { providerEnum } from "src/utils/enum"; +import * as bcrypt from "bcryptjs"; @Injectable() export class NaverOAuthStrategy extends PassportStrategy(Strategy, "naver") { @@ -23,10 +25,13 @@ export class NaverOAuthStrategy extends PassportStrategy(Strategy, "naver") { const { email, id, nickname } = profile; const user = new User(); + const salt = await bcrypt.genSalt(); + const hashedPassword = await bcrypt.hash(id, salt); + user.email = email; user.userId = id + "*naver"; user.nickname = nickname; - user.password = "naver"; + user.password = hashedPassword; user.provider = providerEnum.NAVER; return user; From 7fe8c1c935a2c928becf4a1719bae4284f1eebae Mon Sep 17 00:00:00 2001 From: jeongmin Date: Tue, 5 Dec 2023 14:28:20 +0900 Subject: [PATCH 6/8] =?UTF-8?q?chore:=20=EB=94=94=EB=B2=84=EA=B9=85=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/src/auth/strategies/kakao.strategy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BE/src/auth/strategies/kakao.strategy.ts b/BE/src/auth/strategies/kakao.strategy.ts index d427e8a..4b115c7 100644 --- a/BE/src/auth/strategies/kakao.strategy.ts +++ b/BE/src/auth/strategies/kakao.strategy.ts @@ -37,9 +37,9 @@ export class KakaoStrategy extends PassportStrategy(Strategy) { user.password = hashedPassword; user.provider = providerEnum.KAKAO; + console.log(user); done(null, user); } catch (error) { - console.log(error); done( new BadRequestException( `카카오 로그인 중 오류가 발생했습니다 : ${error.message}`, From 3bb78707d3d11bea7d48cd5eb320054b4fa26d79 Mon Sep 17 00:00:00 2001 From: jeongmin Date: Tue, 5 Dec 2023 15:00:04 +0900 Subject: [PATCH 7/8] =?UTF-8?q?fix:=20kakao=20strategy=20=EB=82=B4?= =?UTF-8?q?=EB=B6=80=20callbackURL=20=ED=99=98=EA=B2=BD=EB=B3=80=EC=88=98?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/src/auth/strategies/kakao.strategy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BE/src/auth/strategies/kakao.strategy.ts b/BE/src/auth/strategies/kakao.strategy.ts index 4b115c7..4e8e542 100644 --- a/BE/src/auth/strategies/kakao.strategy.ts +++ b/BE/src/auth/strategies/kakao.strategy.ts @@ -12,7 +12,7 @@ export class KakaoStrategy extends PassportStrategy(Strategy) { super({ clientID: process.env.KAKAO_CLIENT_ID, clientSecret: process.env.KAKAO_CLIENT_SECRET, - callbackURL: `${process.env.BACKEND_URL}/auth/kakao/callback`, + callbackURL: `${process.env.FRONTEND_URL}/auth/kakao/callback`, }); } From b906398ae315217bc6dab5a655d286e14e05dc19 Mon Sep 17 00:00:00 2001 From: jeongmin Date: Tue, 5 Dec 2023 15:54:01 +0900 Subject: [PATCH 8/8] =?UTF-8?q?chore:=20=EB=94=94=EB=B2=84=EA=B9=85=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/src/auth/strategies/kakao.strategy.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/BE/src/auth/strategies/kakao.strategy.ts b/BE/src/auth/strategies/kakao.strategy.ts index 4e8e542..6252024 100644 --- a/BE/src/auth/strategies/kakao.strategy.ts +++ b/BE/src/auth/strategies/kakao.strategy.ts @@ -37,7 +37,6 @@ export class KakaoStrategy extends PassportStrategy(Strategy) { user.password = hashedPassword; user.provider = providerEnum.KAKAO; - console.log(user); done(null, user); } catch (error) { done(