Skip to content

Commit

Permalink
feat: 카카오 로그인 (#23)
Browse files Browse the repository at this point in the history
* feat: REAT API kakao login

* feat: /auth swagger 반영

* docs: Auth server 콘솔 출력

* chore: remove generic

* feat: 카카오계정 간편로그인
&prompt=select_account

* feat: /kakao/unlink

* format: fix prettier line separator `lf`

* fix: memberExcel > memberFile
  • Loading branch information
w8385 authored May 7, 2024
1 parent 4a18d65 commit 94e893d
Show file tree
Hide file tree
Showing 9 changed files with 203 additions and 18 deletions.
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
"^[./]"
],
"importOrderSeparation": true,
"importOrderSortSpecifiers": true
"importOrderSortSpecifiers": true,
"endOfLine": "lf"
}
33 changes: 28 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@nestjs/axios": "^3.0.2",
"@nestjs/common": "^10.0.0",
"@nestjs/config": "^3.2.1",
"@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/swagger": "^7.3.1",
"@types/xlsx-populate": "github:JanLoebel/types-xlsx-populate",
"@typescript-eslint/typescript-estree": "^7.5.0",
"axios": "^1.6.8",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"excel4node": "^1.8.2",
Expand Down
47 changes: 44 additions & 3 deletions src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,49 @@
import { Controller } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Controller, Get, Post, Query } from '@nestjs/common';
import { ApiQuery, ApiTags } from '@nestjs/swagger';

import { AuthService } from './auth.service';

@ApiTags('Auth')
@Controller('auth')
export class AuthController {
constructor() {}
constructor(private readonly authService: AuthService) {}

@Get('kakao/callback')
async kakaoCallback(
@Query('code') code: string,
// @Query('error') error: string,
// @Query('error_description') error_description: string,
// @Query('state') state: string,
) {
return this.authService.kakaoCallback(
code,
// error,
// error_description,
// state,
);
}

@Post('kakao/token')
@ApiQuery({ name: 'code', required: true })
async kakaoToken(@Query('code') code: string) {
return this.authService.kakaoToken(code);
}

@Post('kakao/login')
@ApiQuery({ name: 'kakaoToken', required: true })
async kakaoLogin(@Query('kakaoToken') kakaoToken: string) {
return this.authService.kakaoLogin(kakaoToken);
}

@Post('kakao/logout')
@ApiQuery({ name: 'kakaoToken', required: true })
async kakaoLogout(@Query('kakaoToken') kakaoToken: string) {
return this.authService.kakaoLogout(kakaoToken);
}

@Post('kakao/unlink')
@ApiQuery({ name: 'kakaoToken', required: true })
async kakaoUnlink(@Query('kakaoToken') kakaoToken: string) {
return this.authService.kakaoUnlink(kakaoToken);
}
}
3 changes: 3 additions & 0 deletions src/auth/auth.module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { HttpModule } from '@nestjs/axios';
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';

import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';

@Module({
imports: [ConfigModule, HttpModule],
controllers: [AuthController],
providers: [AuthService],
})
Expand Down
87 changes: 86 additions & 1 deletion src/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,89 @@
import { HttpService } from '@nestjs/axios';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { firstValueFrom } from 'rxjs';

@Injectable()
export class AuthService {}
export class AuthService {
constructor(
private readonly configService: ConfigService,
private readonly httpService: HttpService,
) {}

kakaoCallback(
code: string,
// error: string,
// error_description: string,
// state: string,
) {
return code;
}

async kakaoToken(code: string) {
const { data } = await firstValueFrom(
this.httpService.post(
'https://kauth.kakao.com/oauth/token',
{
grant_type: 'authorization_code',
client_id: this.configService.get<string>('KAKAO_REST_API_KEY'),
redirect_uri: this.configService.get<string>('KAKAO_REDIRECT_URI'),
code,
},
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
},
},
),
);

return data['access_token'];
}

async kakaoLogin(kakaoToken: string) {
const { data } = await firstValueFrom(
this.httpService.get('https://kapi.kakao.com/v2/user/me', {
headers: {
Authorization: `Bearer ${kakaoToken}`,
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
},
}),
);

return data;
}

async kakaoLogout(kakaoToken: string) {
const { data } = await firstValueFrom(
this.httpService.post(
'https://kapi.kakao.com/v1/user/logout',
{},
{
headers: {
Authorization: `Bearer ${kakaoToken}`,
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
},
},
),
);

return data;
}

async kakaoUnlink(kakaoToken: string) {
const { data } = await firstValueFrom(
this.httpService.post(
'https://kapi.kakao.com/v1/user/unlink',
{},
{
headers: {
Authorization: `Bearer ${kakaoToken}`,
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
},
},
),
);

return data;
}
}
39 changes: 32 additions & 7 deletions src/common/configs/swagger.config.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,63 @@
import { INestApplication } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import * as process from 'node:process';

import { AuthModule } from '../../auth/auth.module';
import { EventModule } from '../../event/event.module';
import { GroupModule } from '../../group/group.module';
import { MemberModule } from '../../member/member.module';
import { TransactionModule } from '../../transaction/transaction.module';
import { UserModule } from '../../user/user.module';

export const swaggerConfig = (app: INestApplication<any>) => {
export const swaggerConfig = (app: INestApplication) => {
const config = new DocumentBuilder()
.setTitle('sometime API')
.addTag('Group', '모임 관련 API')
.addTag('Member', '모임 회원 관련 API')
.addTag('Event', '이벤트 관련 API')
.addTag('Auth', 'OAuth 인증 관련 API')
.addTag('User', '사용자 관련 API')
.addTag('Transaction', '거래 내역 관련 API')
.build();

const document = SwaggerModule.createDocument(app, config, {
include: [GroupModule, MemberModule, EventModule, UserModule],
include: [GroupModule, MemberModule, EventModule, TransactionModule],
});
SwaggerModule.setup('api', app, document);
};

export const devSwaggerConfig = (app: INestApplication<any>) => {
export const devSwaggerConfig = (app: INestApplication) => {
const config = new DocumentBuilder()
.setTitle('sometime API')
.addTag('Debug', '개발용 API')
.addTag('Group', '모임 관련 API')
.addTag('Member', '모임 회원 관련 API')
.addTag('Event', '이벤트 관련 API')
.addTag('Auth', 'OAuth 인증 관련 API')
.addTag('User', '사용자 관련 API')
.addTag('Transaction', '거래 내역 관련 API')
.build();

const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('dev', app, document);
};

export const authSwaggerConfig = (app: INestApplication) => {
const authorizationUrl = `https://kauth.kakao.com/oauth/authorize?client_id=${process.env.KAKAO_REST_API_KEY}&redirect_uri=${process.env.KAKAO_REDIRECT_URI}&response_type=code&prompt=select_account`;
const config = new DocumentBuilder()
.setTitle('sometime API')
.addTag('Auth', 'OAuth 인증 관련 API')
.addTag('User', '사용자 관련 API')
.addOAuth2({
type: 'oauth2',
flows: {
authorizationCode: {
authorizationUrl,
// tokenUrl: 'https://kauth.kakao.com/oauth/token',
scopes: undefined,
},
},
})
.build();

const document = SwaggerModule.createDocument(app, config, {
include: [AuthModule, UserModule],
});
SwaggerModule.setup('auth', app, document);
};
2 changes: 1 addition & 1 deletion src/group/dto/upload-group.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ export class UploadGroupDto extends CreateGroupDto {
type: 'file',
format: 'binary',
})
readonly memberExcel: Express.Multer.File | undefined;
readonly memberFile: Express.Multer.File | undefined;
}
5 changes: 5 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as process from 'process';

import { AppModule } from './app.module';
import {
authSwaggerConfig,
devSwaggerConfig,
swaggerConfig,
} from './common/configs/swagger.config';
Expand All @@ -12,6 +13,7 @@ async function bootstrap() {
const app = await NestFactory.create(AppModule);
swaggerConfig(app);
devSwaggerConfig(app);
authSwaggerConfig(app);
app.useGlobalPipes(new ValidationPipe());
app.enableCors();
await app.listen(process.env.SERVER_PORT);
Expand All @@ -24,4 +26,7 @@ bootstrap().then(() => {
console.log(
`Dev server running on http://localhost:${process.env.SERVER_PORT}/dev`,
);
console.log(
`Auth server running on http://localhost:${process.env.SERVER_PORT}/auth`,
);
});

0 comments on commit 94e893d

Please sign in to comment.