Skip to content

Commit

Permalink
feat: auth controller 추가, 42 access token 발급 (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
yubinquitous committed Nov 2, 2023
1 parent 3884f22 commit 18f5445
Show file tree
Hide file tree
Showing 17 changed files with 285 additions and 9 deletions.
2 changes: 1 addition & 1 deletion api-gateway-config
61 changes: 56 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 @@ -22,7 +22,9 @@
"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/mapped-types": "*",
"@nestjs/platform-express": "^10.0.0",
"axios": "^1.6.0",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1"
},
Expand Down
12 changes: 9 additions & 3 deletions src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { Module } from '@nestjs/common';
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { LoggerMiddleware } from './common/middlewares/logger.middleware';

@Module({
imports: [],
imports: [AuthModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggerMiddleware).forRoutes('*');
}
}
52 changes: 52 additions & 0 deletions src/auth/auth-fortytwo.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Injectable, Logger, UnauthorizedException } from '@nestjs/common';
import axios from 'axios';
import { FortyTwoUserDto } from './dto/fortytwo-user.dto';

@Injectable()
export class AuthFortyTwoService {
private readonly logger = new Logger(AuthFortyTwoService.name);
private readonly baseUrl = 'https://api.intra.42.fr';

async getAccessToken(code: string): Promise<string> {
try {
const response = await axios.post(
`${this.baseUrl}/oauth/token`,
{
grant_type: 'authorization_code',
client_id: process.env.FORTYTWO_CLIENT_ID,
client_secret: process.env.FORTYTWO_CLIEND_SECRET,
code,
redirect_uri: process.env.FORTYTWO_REDIRECT_URI,
},
{
headers: {
'Content-Type': 'application/json',
},
},
);

return response.data.access_token;
} catch (error) {
this.logger.error(error);
throw new UnauthorizedException('Invalid code');
}
}

async getUserData(accessToken: string): Promise<FortyTwoUserDto> {
try {
const response = await axios.get(`${this.baseUrl}/v2/me`, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
const userData: FortyTwoUserDto = {
nickname: response.data.login,
email: response.data.email,
};
return userData;
} catch (error) {
this.logger.error(error);
throw new UnauthorizedException('Invalid access token');
}
}
}
20 changes: 20 additions & 0 deletions src/auth/auth.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';

describe('AuthController', () => {
let controller: AuthController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [AuthController],
providers: [AuthService],
}).compile();

controller = module.get<AuthController>(AuthController);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});
});
25 changes: 25 additions & 0 deletions src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Body, Controller, Post } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthFortyTwoService } from './auth-fortytwo.service';
import { FortyTwoUserDto } from './dto/fortytwo-user.dto';

@Controller('auth')
export class AuthController {
constructor(
private readonly authService: AuthService,
private readonly authFortyTwoService: AuthFortyTwoService,
) {}

@Post('signin')
async signin(@Body() code: string) {
// code를 이용해 access token을 받아온다.
const fortyTwoAccessToken =
await this.authFortyTwoService.getAccessToken(code);
// access token을 이용해 42API에서 유저 정보를 받아온다.
const fortyTwoUserDto: FortyTwoUserDto =
await this.authFortyTwoService.getUserData(fortyTwoAccessToken);

// 유저 정보를 이용해 유저를 찾는다.
const user = await this.authService.validateUser(fortyTwoUserDto);
}
}
10 changes: 10 additions & 0 deletions src/auth/auth.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { AuthFortyTwoService } from './auth-fortytwo.service';

@Module({
controllers: [AuthController],
providers: [AuthService, AuthFortyTwoService],
})
export class AuthModule {}
18 changes: 18 additions & 0 deletions src/auth/auth.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AuthService } from './auth.service';

describe('AuthService', () => {
let service: AuthService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [AuthService],
}).compile();

service = module.get<AuthService>(AuthService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
15 changes: 15 additions & 0 deletions src/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Injectable, Logger } from '@nestjs/common';
import { FortyTwoUserDto } from './dto/fortytwo-user.dto';

@Injectable()
export class AuthService {
private readonly logger = new Logger(AuthService.name);

// constructor(private readonly connection: Connection) {}

async validateUser(userData: FortyTwoUserDto) {
// const queryRunner = this.connection.createQueryRunner();
// 유저 정보를 이용해 유저를 찾는다.
// const user = await this.
}
}
1 change: 1 addition & 0 deletions src/auth/dto/create-auth.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export class CreateAuthDto {}
4 changes: 4 additions & 0 deletions src/auth/dto/fortytwo-user.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export class FortyTwoUserDto {
nickname: string;
email: string;
}
4 changes: 4 additions & 0 deletions src/auth/dto/update-auth.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreateAuthDto } from './create-auth.dto';

export class UpdateAuthDto extends PartialType(CreateAuthDto) {}
1 change: 1 addition & 0 deletions src/auth/entities/auth.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export class Auth {}
20 changes: 20 additions & 0 deletions src/common/interceptors/logger.interceptor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
console.log('Before...');

const now = Date.now();
return next
.handle()
.pipe(tap(() => console.log(`After... ${Date.now() - now}ms`)));
}
}
29 changes: 29 additions & 0 deletions src/common/interceptors/transform.interceptor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

export interface Response<T> {
data: T;
}

@Injectable()
export class TransformInterceptor<T>
implements NestInterceptor<T, Response<T>>
{
intercept(
context: ExecutionContext,
next: CallHandler,
): Observable<Response<T>> {
return next.handle().pipe(
map((data) => ({
success: true,
data,
})),
);
}
}
18 changes: 18 additions & 0 deletions src/common/middlewares/logger.middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Injectable, Logger, NestMiddleware } from '@nestjs/common';
import { NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
private logger = new Logger('HTTP');

use(req: any, res: any, next: NextFunction) {
res.on('finish', () => {
this.logger.log(
`${req.ip} ${req.method} ${res.statusCode}`,
req.originalUrl,
);
});

next();
}
}

0 comments on commit 18f5445

Please sign in to comment.