Skip to content

Commit

Permalink
Merge pull request #17 from raipen/feat/google-login
Browse files Browse the repository at this point in the history
Feat: google login
  • Loading branch information
raipen authored Mar 29, 2024
2 parents 90fdc00 + 2817c4c commit fcc0620
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 18 deletions.
4 changes: 2 additions & 2 deletions src/DTO/oauth.dto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SchemaToInterface } from 'fastify-schema-to-ts';

export const kakaoSchema = {
export const oauthRedirctSchema = {
tags: ['User'],
summary: '로그인',
querystring: {
Expand All @@ -16,4 +16,4 @@ export const kakaoSchema = {
},
} as const;

export type kakaoInterface = SchemaToInterface<typeof kakaoSchema>;
export type oauthRedirctInterface = SchemaToInterface<typeof oauthRedirctSchema>;
14 changes: 12 additions & 2 deletions src/back/api/routes/oauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,26 @@ import * as Oauth from '@DTO/oauth.dto';
import OauthService from '@services/oauth.service';

const api: FastifyPluginAsync = async (server: FastifyInstance) => {
server.get<Oauth.kakaoInterface>(
server.get<Oauth.oauthRedirctInterface>(
'/kakao',
{
schema: Oauth.kakaoSchema
schema: Oauth.oauthRedirctSchema
},
async (request, reply) => {
const { accessToken, refreshToken } = await OauthService.kakao(request.query);
reply.setCookie('authorization', refreshToken).redirect(303, `/login/${accessToken}`);
}
);
server.get<Oauth.oauthRedirctInterface>(
'/google',
{
schema: Oauth.oauthRedirctSchema
},
async (request, reply) => {
const { accessToken, refreshToken } = await OauthService.google(request.query);
reply.setCookie('authorization', refreshToken).redirect(303, `/login/${accessToken}`);
}
);
};

export default api;
4 changes: 3 additions & 1 deletion src/back/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ class Config{
jwtRefreshKey: process.env.JWT_REFRESH_KEY || 'refresh',
salt: process.env.SALT || 'salt',
kakaoClientId: process.env.KAKAO_CLIENT_ID || 'kakaoClientId',
kakaoRedirectUri: process.env.KAKAO_REDIRECT_URI || 'kakaoRedirectUri',
redirectUri: process.env.REDIRECT_URI || 'RedirectUri',
googleClientId: process.env.GOOGLE_CLIENT_ID || 'googleClientId',
googleClientSecret: process.env.GOOGLE_CLIENT_SECRET || 'googleClientSecret',
nodeEnv: process.env.NODE_ENV,
} as const;
}
Expand Down
1 change: 1 addition & 0 deletions src/back/loaders/errorHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default (
request: FastifyRequest,
reply: FastifyReply
) => {
console.error(error);
if (error instanceof ErrorWithToast) return handleKnownError(error, reply);
if (error.validation) {
return reply.code(400).send({
Expand Down
34 changes: 33 additions & 1 deletion src/back/repository/oauth.repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const getKakaoAccessToken = async (code: string) => {
data: qs.stringify({
grant_type: 'authorization_code',
client_id: config.kakaoClientId,
redirect_uri: config.kakaoRedirectUri,
redirect_uri: config.redirectUri+'/api/v1/oauth/kakao',
code
}),
headers: {
Expand Down Expand Up @@ -46,3 +46,35 @@ export const getKakaoUserInfo = async (kakaoAccessToken: string) => {
nickname: kakao_account.profile?.nickname,
};
}

export const getGoogleAccessToken = async (code: string) => {
const {access_token: getGoogleAccessToken} = (await axios<{access_token:string,scope:string}>({
method: 'post',
url: 'https://oauth2.googleapis.com/token',
data: qs.stringify({
grant_type: 'authorization_code',
client_id: config.googleClientId,
redirect_uri: config.redirectUri+'/api/v1/oauth/google',
client_secret: config.googleClientSecret,
code
}),
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
}
})).data;
console.log(getGoogleAccessToken);
return getGoogleAccessToken;
}

export const getGoogleUserInfo = async (getGoogleAccessToken: string) => {
const { id, name } = (await axios.get<{id?:string,name?:string}>('https://www.googleapis.com/userinfo/v2/me', {
headers: {
Authorization: `Bearer ${getGoogleAccessToken}`,
}
})).data;
return {
id,
name
};
}

23 changes: 21 additions & 2 deletions src/back/services/oauth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { LoginToken } from '@serverUtils/jwt';
import * as OauthDTO from '@DTO/oauth.dto';
import * as UserRepo from '@repository/user.repo';
import { NotFoundError, NotCorrectTypeError, ExistError } from '@errors';
import { getKakaoAccessToken, getKakaoId, getKakaoUserInfo } from '@repository/oauth.repo';
import { getKakaoAccessToken, getKakaoId, getKakaoUserInfo, getGoogleAccessToken, getGoogleUserInfo } from '@repository/oauth.repo';

export default {
async kakao({code,error}: OauthDTO.kakaoInterface['Querystring']){
async kakao({code,error}: OauthDTO.oauthRedirctInterface['Querystring']){
if(error) throw new NotCorrectTypeError("", "code");
if(!code) throw new NotFoundError("", "code");
const kakaoAccessToken = await getKakaoAccessToken(code);
Expand All @@ -25,4 +25,23 @@ export default {
refreshToken
};
},
async google({code,error}: OauthDTO.oauthRedirctInterface['Querystring']){
if(error) throw new NotCorrectTypeError("", "code");
if(!code) throw new NotFoundError("", "code");
const googleAccessToken = await getGoogleAccessToken(code);
const googleUserInfo = await getGoogleUserInfo(googleAccessToken);
if(!googleUserInfo.id) throw new NotFoundError("", "id");
if(!googleUserInfo.name) throw new NotFoundError("", "name");
let user = await UserRepo.getUser('GOOGLE', googleUserInfo.id);
if(!user) {
user = await UserRepo.createUser({name: googleUserInfo.name, socialId: googleUserInfo.id, socialType: 'GOOGLE'});
}
const loginToken = new LoginToken(user.uuid);
const accessToken = loginToken.signAccessToken();
const refreshToken = loginToken.signRefreshToken();
return {
accessToken,
refreshToken
};
}
}
16 changes: 16 additions & 0 deletions src/front/assets/googlelogin.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 7 additions & 1 deletion src/front/pages/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Link } from 'react-router-dom';
import kakaologin from '@assets/kakaologin.png';
import googlelogin from '@assets/googlelogin.svg';
import { LoginContainer} from '@components';

function Login() {
Expand All @@ -9,9 +10,14 @@ function Login() {
<h1>로그인</h1>
<Link
style={{display: "block", margin: "0 auto"}}
to={`https://kauth.kakao.com/oauth/authorize?client_id=${import.meta.env.KAKAO_CLIENT_ID}&redirect_uri=${import.meta.env.KAKAO_REDIRECT_URI}&response_type=code`}>
to={`https://kauth.kakao.com/oauth/authorize?client_id=${__KAKAO_CLIENT_ID__}&redirect_uri=${__REDIRECT_URI__}/api/v1/oauth/kakao&response_type=code`}>
<img src={kakaologin} alt="카카오 로그인" width="200"/>
</Link>
<Link
style={{display: "block", margin: "0 auto"}}
to={`https://accounts.google.com/o/oauth2/v2/auth?client_id=${__GOOGLE_CLIENT_ID__}&redirect_uri=${__REDIRECT_URI__}/api/v1/oauth/google&response_type=code&scope=https://www.googleapis.com/auth/userinfo.profile`}>
<img src={googlelogin} alt="구글 로그인" width="200"/>
</Link>
</LoginContainer>
);
}
Expand Down
12 changes: 4 additions & 8 deletions src/front/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly KAKAO_CLIENT_ID: string
readonly KAKAO_REDIRECT_URI: string
}

interface ImportMeta {
readonly env: ImportMetaEnv
}

declare const __REDIRECT_URI__: string;
declare const __GOOGLE_CLIENT_ID__: string;
declare const __KAKAO_CLIENT_ID__: string;
10 changes: 9 additions & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
import _ from 'json-bigint';
import dotenv from 'dotenv';

dotenv.config();

// https://vitejs.dev/config/
export default defineConfig({
root: 'src/front',
envDir: '../../',
envPrefix: ['VITE_', 'KAKAO_'],
define: {
__REDIRECT_URI__: JSON.stringify(process.env.REDIRECT_URI),
__GOOGLE_CLIENT_ID__: JSON.stringify(process.env.GOOGLE_CLIENT_ID),
__KAKAO_CLIENT_ID__: JSON.stringify(process.env.KAKAO_CLIENT_ID),
},
plugins: [react(), tsconfigPaths()],
server: {
port: 3000,
Expand Down

0 comments on commit fcc0620

Please sign in to comment.