Skip to content

Commit

Permalink
[refactor] #4 #5 소셜 로그인 서버 로직 추상화
Browse files Browse the repository at this point in the history
- 공통 로직 전부 추상화하여 사용
  • Loading branch information
comeintostout committed Nov 16, 2022
1 parent 38134dc commit 73fcab5
Show file tree
Hide file tree
Showing 3 changed files with 1,988 additions and 210 deletions.
86 changes: 19 additions & 67 deletions backend/src/user/user.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Body, Controller, Get, Post, Query, Res } from '@nestjs/common';
import { Body, Controller, Get, Param, Post, Query, Res } from '@nestjs/common';
import { Response } from 'express';
import { socialPlatform } from './user.enum';
import { UserService } from './user.service';
Expand All @@ -9,83 +9,35 @@ export class UserController {

@Get('login')
loginRedirect(@Query('social') social: socialPlatform, @Res() res: Response) {
const naverOauthUrl =
'https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=' +
process.env.NAVER_OAUTH_CLIENT_ID +
'&redirect_uri=' +
'http://localhost:3333/user/callback/naver' +
'&state=' +
'RANDOM_STATE';

const kakaoOauthUrl = `https://kauth.kakao.com/oauth/authorize?client_id=${process.env.KAKAO_REST_API_KEY}&redirect_uri=http://localhost:3333/user/callback/kakao&response_type=code`;
const googleOauthUrl = `https://accounts.google.com/o/oauth2/v2/auth?scope=https://www.googleapis.com/auth/userinfo.profile&response_type=code&redirect_uri=http://localhost:3333/user/callback/google&client_id=${process.env.GOOGLE_OAUTH_CLIENT_ID}`;

switch (social) {
case socialPlatform.NAVER:
res.redirect(naverOauthUrl);
break;
case socialPlatform.KAKAO:
res.redirect(kakaoOauthUrl);
break;
case socialPlatform.GOOGLE:
res.redirect(googleOauthUrl);
break;
}
}

@Get('callback/google')
async googleCallback(@Query('code') code: string, @Res() res: Response) {
const access_token = await this.userService.googleOauth(code);
const googleProfile = await this.userService.googleProfileSearch(
access_token
);
const userData = await this.userService.findUser(
socialPlatform.GOOGLE,
googleProfile.id
);
if (!userData) {
return res.redirect('http://localhost:5173/signup'); // 가입으로 보내요
} else {
return res.redirect('http://localhost:5173'); // 쿠기 생성해서 메인으로 보내요
}
const socialOauthUrl = {
naver: `https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=${process.env.NAVER_OAUTH_CLIENT_ID}&redirect_uri=${process.env.SERVER_URL}/user/callback/naver&state=RANDOM_STATE`,
kakao: `https://kauth.kakao.com/oauth/authorize?client_id=${process.env.KAKAO_REST_API_KEY}&redirect_uri=${process.env.SERVER_URL}/user/callback/kakao&response_type=code`,
google: `https://accounts.google.com/o/oauth2/v2/auth?scope=https://www.googleapis.com/auth/userinfo.profile&response_type=code&redirect_uri=${process.env.SERVER_URL}/user/callback/google&client_id=${process.env.GOOGLE_OAUTH_CLIENT_ID}`,
};
res.redirect(socialOauthUrl[social]);
}

@Get('callback/kakao')
async kakaoCallback(@Query('code') code: string, @Res() res: Response) {
const access_token = await this.userService.kakaoOauth(code);
const kakaoProfile = await this.userService.kakaoProfileSearch(
access_token
);
console.log(kakaoProfile);
const userData = await this.userService.findUser(
socialPlatform.KAKAO,
kakaoProfile.id
);
if (!userData) {
return res.redirect('http://localhost:5173/signup'); // 가입으로 보내요
} else {
return res.redirect('http://localhost:5173'); // 쿠기 생성해서 메인으로 보내요
}
}

@Get('callback/naver')
async naverCallback(
@Get('callback/:social')
async socialCallback(
@Query('code') code: string,
@Query('state') state: string,
@Param('social') social: socialPlatform,
@Res() res: Response
) {
const access_token = await this.userService.naverOauth(code, state);
const naverProfile = await this.userService.naverProfileSearch(
const access_token = await this.userService.socialOauth(social, code);
const userSocialProfile = await this.userService.socialProfileSearch(
social,
access_token
);
console.log(userSocialProfile);
const userData = await this.userService.findUser(
socialPlatform.NAVER,
naverProfile.id
social,
userSocialProfile.id
);

if (!userData) {
return res.redirect('http://localhost:5173/signup'); // 가입으로 보내요
return res.redirect(process.env.CLIENT_URL + '/signup'); // 가입으로 보내요
} else {
return res.redirect('http://localhost:5173'); // 쿠기 생성해서 메인으로 보내요
return res.redirect(process.env.CLIENT_URL); // 쿠기 생성해서 메인으로 보내요
}
}

Expand Down
131 changes: 45 additions & 86 deletions backend/src/user/user.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { HttpService } from '@nestjs/axios';
import { Injectable } from '@nestjs/common';
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { firstValueFrom } from 'rxjs';
import { Repository } from 'typeorm';
Expand All @@ -19,108 +19,67 @@ export class UserService {
return saveResult;
}

async googleOauth(code: string) {
const api_url = `https://oauth2.googleapis.com/token?code=${code}&client_id=${process.env.GOOGLE_OAUTH_CLIENT_ID}&client_secret=${process.env.GOOGLE_OAUTH_SECRET}&redirect_uri=http://localhost:3333/user/callback/google&grant_type=authorization_code`;
async socialOauth(social: socialPlatform, code: string) {
const url = {
naver: `https://nid.naver.com/oauth2.0/token?grant_type=authorization_code&client_id=${process.env.NAVER_OAUTH_CLIENT_ID}&client_secret=${process.env.NAVER_OAUTH_SECRET}&redirect_uri=${process.env.SERVER_URL}/user/callback/naver
&code=${code}&state=RANDOM_STATE`,
kakao: `https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id=${process.env.KAKAO_REST_API_KEY}&redirect_url=${process.env.SERVER_URL}/user/callback/kakao&code=${code}`,
google: `https://oauth2.googleapis.com/token?code=${code}&client_id=${process.env.GOOGLE_OAUTH_CLIENT_ID}&client_secret=${process.env.GOOGLE_OAUTH_SECRET}&redirect_uri=${process.env.SERVER_URL}/user/callback/google&grant_type=authorization_code`,
};

const googleOauthResponse = await firstValueFrom(
this.httpService.post(api_url)
const socialOauthResponse = await firstValueFrom(
this.httpService.post(url[social])
);
const access_token = googleOauthResponse.data.access_token;
const access_token = socialOauthResponse.data.access_token;
return access_token;
}

async kakaoOauth(code: string) {
const api_url = `https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id=${process.env.KAKAO_REST_API_KEY}&redirect_url=http://localhost:3333/user/callback/kakao&code=${code}`;
async socialProfileSearch(social: socialPlatform, access_token: string) {
const profileSearchUrl = {
naver: 'https://openapi.naver.com/v1/nid/me',
kakao: 'https://kapi.kakao.com/v2/user/me',
google: 'https://www.googleapis.com/oauth2/v2/userinfo',
};

const kakaoOauthResponse = await firstValueFrom(
this.httpService.post(api_url)
);
const access_token = kakaoOauthResponse.data.access_token;
return access_token;
}

async naverOauth(code: string, state: string) {
const api_url =
'https://nid.naver.com/oauth2.0/token?grant_type=authorization_code&client_id=' +
process.env.NAVER_OAUTH_CLIENT_ID +
'&client_secret=' +
process.env.NAVER_OAUTH_SECRET +
'&redirect_uri=' +
'http://localhost:3333/user/callback/naver' +
'&code=' +
code +
'&state=' +
state;

const naverOauthResponse = await firstValueFrom(
this.httpService.get(api_url, {
headers: {
'X-Naver-Client-Id': process.env.NAVER_OAUTH_CLIENT_ID,
'X-Naver-Client-Secret': process.env.NAVER_OAUTH_SECRET,
},
})
);

const { access_token } = naverOauthResponse.data;
return access_token;
}

async googleProfileSearch(access_token: string) {
try {
console.log(access_token);
const googleProfileApiResponse = await firstValueFrom(
this.httpService.get(`https://www.googleapis.com/oauth2/v2/userinfo`, {
const socialProfileSearchApiResponse = await firstValueFrom(
this.httpService.get(profileSearchUrl[social], {
headers: {
Authorization: 'Bearer ' + access_token,
Authorization: `Bearer ${access_token}`,
},
})
);
const { id, picture } = googleProfileApiResponse.data.id;

return { id, picture };
const socialProfileData = socialProfileSearchApiResponse.data;
const returnData = {
id: '',
profileImg: '',
};

switch (social) {
case socialPlatform.NAVER:
returnData.id = socialProfileData.response.id;
returnData.profileImg = socialProfileData.response.profile_image;
return returnData;
case socialPlatform.KAKAO:
returnData.id = socialProfileData.id;
returnData.profileImg =
socialProfileData.kakao_account.profile.profile_image_url;
return returnData;
case socialPlatform.GOOGLE:
returnData.id = socialProfileData.id;
returnData.profileImg = socialProfileData.picture;
return returnData;
default:
throw new NotFoundException();
}
} catch (e) {
console.log(e);
return;
}
}

async kakaoProfileSearch(access_token: string) {
try {
const kakaoProfileApiResponse = await firstValueFrom(
this.httpService.get('https://kapi.kakao.com/v2/user/me', {
headers: {
Authorization: 'Bearer ' + access_token,
'Content-type': 'application/x-www-form-urlencoded;charset=utf-8',
},
})
throw new NotFoundException(
'OAUTH에서 해당 사용자를 조회할 수 없습니다.'
);

const id = kakaoProfileApiResponse.data.id;
const email = kakaoProfileApiResponse.data.kakao_account.email;
const profile_image =
kakaoProfileApiResponse.data.kakao_account.profile.profile_image_url;
return { id, email, profile_image };
} catch (e) {
console.log(e);
return;
}
}

async naverProfileSearch(access_token: string) {
const url = 'https://openapi.naver.com/v1/nid/me';

const naverProfileApiResponse = await firstValueFrom(
this.httpService.get(url, {
headers: {
Authorization: 'Bearer ' + access_token,
},
})
);

const { id, profile_image, email } = naverProfileApiResponse.data.response;
return { id, profile_image, email };
}

async findUser(social: socialPlatform, id: string): Promise<User> {
const findResult = await this.userRepository.findOneBy({ id, social });
return findResult;
Expand Down
Loading

0 comments on commit 73fcab5

Please sign in to comment.