Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/modules/classification/classification.v2.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
UseGuards,
} from '@nestjs/common';
import { BasePaginationQuery, GetUser } from '@src/common';
import { JwtGuard } from '../users/guards';
import { JwtV2Guard } from '../users/guards/jwt.v2.guard';
import { ClassificationV2Service } from './classification.v2.service';
import {
ClassificationControllerDocs,
Expand All @@ -27,7 +27,7 @@ import { AIFolderNameListResponse } from './response/ai-folder-list.dto';
import { AIPostListResponse } from './response/ai-post-list.dto';

@Controller({ version: '2', path: 'classification' })
@UseGuards(JwtGuard)
@UseGuards(JwtV2Guard)
@ClassificationControllerDocs
export class ClassificationV2Controller {
constructor(
Expand Down
4 changes: 2 additions & 2 deletions src/modules/folders/folders.v2.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { GetUser } from '@src/common';
import { ClassificationV2Service } from '../classification/classification.v2.service';
import { GetPostQueryDto } from '../posts/dto/find-in-folder.dto';
import { PostsService } from '../posts/posts.service';
import { JwtGuard } from '../users/guards/jwt.guard';
import { JwtV2Guard } from '../users/guards/jwt.v2.guard';
import {
CreateFolderDocs,
DeleteFolderDocs,
Expand All @@ -33,7 +33,7 @@ import {
import { PostResponse } from './responses/post.response';

@FolderControllerDocs
@UseGuards(JwtGuard)
@UseGuards(JwtV2Guard)
@Controller({ version: '2', path: 'folders' })
export class FoldersV2Controller {
constructor(
Expand Down
33 changes: 33 additions & 0 deletions src/modules/users/guards/jwt.v2.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { PublicRouteToken } from '@src/common';
import { JWT_V2_STRATEGY_TOKEN } from '@src/modules/users/guards/strategy/strategy.token';

@Injectable()
export class JwtV2Guard extends AuthGuard(JWT_V2_STRATEGY_TOKEN) {
constructor(private readonly reflector: Reflector) {
super();
}

async canActivate(context: ExecutionContext): Promise<boolean> {
// Handler 혹은 Class중 하나만 정의되어있다면 boolean으로 둘다 정의되어있다면 array([boolean,boolean])로 옵니다
const publicMetadata = this.reflector.getAllAndMerge(PublicRouteToken, [
context.getClass(),
context.getHandler(),
]);

// Handler와 Class모두 메타데이터가 정의되어있는 경우
if (
(Array.isArray(publicMetadata) && publicMetadata.length) ||
typeof publicMetadata === 'boolean'
) {
try {
return (await super.canActivate(context)) as boolean;
} catch (err) {
return true;
}
}
return (await super.canActivate(context)) as boolean;
}
}
38 changes: 38 additions & 0 deletions src/modules/users/guards/strategy/jwt.v2.strategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { DataSource } from 'typeorm';
import { JwtPayload, ReqUserPayload } from '@src/common/types/type';
import { User } from '@src/infrastructure/database/entities/user.entity';
import { JWT_V2_STRATEGY_TOKEN } from './strategy.token';

@Injectable()
export class JwtV2Strategy extends PassportStrategy(
Strategy,
JWT_V2_STRATEGY_TOKEN,
) {
constructor(
private readonly dataSource: DataSource,
private readonly config: ConfigService,
) {
super({
secretOrKey: config.get<string>('JWT_SECRET'),
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
});
}

async validate(payload: JwtPayload): Promise<ReqUserPayload> {
const user = await this.dataSource.manager.findOne(User, {
where: {
id: payload.id,
},
});
if (!user) {
throw new UnauthorizedException('인증에 실패하였습니다.');
}
return {
id: payload.id,
};
}
}
1 change: 1 addition & 0 deletions src/modules/users/guards/strategy/strategy.token.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const JWT_STRATEGY_TOKEN = 'jwt';
export const JWT_V2_STRATEGY_TOKEN = 'jwt-v2';
36 changes: 31 additions & 5 deletions src/modules/users/users.module.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,48 @@
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { Folder, FolderSchema, User, UserSchema } from '@src/infrastructure';
import { TypeOrmModule } from '@nestjs/typeorm';
import {
Folder as FolderMongoEntity,
FolderSchema,
User as UserMongoEntity,
UserSchema,
} from '@src/infrastructure';
import { Folder } from '@src/infrastructure/database/entities/folder.entity';
import { User } from '@src/infrastructure/database/entities/user.entity';
import { AuthModule } from '../auth/auth.module';
import { FoldersPGRepository } from '../folders/folders.pg.repository';
import { FolderRepository } from '../folders/folders.repository';
import { JwtStrategy } from './guards/strategy';
import { JwtV2Strategy } from './guards/strategy/jwt.v2.strategy';
import { UsersController } from './users.controller';
import { UsersPGRepository } from './users.pg.repository';
import { UsersRepository } from './users.repository';
import { UsersService } from './users.service';
import { UsersV2Controller } from './users.v2.controller';
import { UsersV2Service } from './users.v2.service';

@Module({
imports: [
AuthModule,
TypeOrmModule.forFeature([Folder, User]),
/** @deprecated */
MongooseModule.forFeature([
{ name: User.name, schema: UserSchema },
{ name: Folder.name, schema: FolderSchema },
{ name: UserMongoEntity.name, schema: UserSchema },
{ name: FolderMongoEntity.name, schema: FolderSchema },
]),
],
controllers: [UsersController],
providers: [UsersService, UsersRepository, FolderRepository, JwtStrategy],
controllers: [UsersController, UsersV2Controller],
providers: [
UsersV2Service,
UsersPGRepository,
FoldersPGRepository,
JwtV2Strategy,

/** @deprecated */
JwtStrategy,
UsersService,
UsersRepository,
FolderRepository,
],
})
export class UsersModule {}
2 changes: 1 addition & 1 deletion src/modules/users/users.pg.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { DataSource, Repository } from 'typeorm';
import { User } from '@src/infrastructure/database/entities/user.entity';

@Injectable()
export class UsersRepository extends Repository<User> {
export class UsersPGRepository extends Repository<User> {
constructor(private dataSource: DataSource) {
super(User, dataSource.createEntityManager());
}
Expand Down
19 changes: 19 additions & 0 deletions src/modules/users/users.v2.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Body, Controller, Post } from '@nestjs/common';
import { CreateUserDocs, UserControllerDocs } from './docs';
import { CreateUserDto } from './dto';
import { CreateUserResponse } from './response';
import { UsersV2Service } from './users.v2.service';

@UserControllerDocs
@Controller({ version: '2', path: 'users' })
export class UsersV2Controller {
constructor(private readonly userService: UsersV2Service) {}

@Post()
@CreateUserDocs
async createUser(@Body() dto: CreateUserDto): Promise<CreateUserResponse> {
const { userId, token } = await this.userService.createUser(dto);
const response = new CreateUserResponse(userId, token);
return response;
}
}
44 changes: 44 additions & 0 deletions src/modules/users/users.v2.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Injectable } from '@nestjs/common';
import { JwtPayload } from 'src/common/types/type';
import { DEFAULT_FOLDER_NAME } from '@src/common/constant';
import { FolderType } from '@src/infrastructure/database/types/folder-type.enum';
import { AuthService } from '../auth/auth.service';
import { FoldersPGRepository } from '../folders/folders.pg.repository';
import { CreateUserDto } from './dto';
import { UsersPGRepository } from './users.pg.repository';

@Injectable()
export class UsersV2Service {
constructor(
private readonly userRepository: UsersPGRepository,
private readonly folderRepository: FoldersPGRepository,
private readonly authService: AuthService,
) {}

async createUser(
dto: CreateUserDto,
): Promise<{ userId: string; token: string }> {
let user = await this.userRepository.findUserByDeviceToken(dto.deviceToken);
if (!user) {
// 새로운 user의 ID
user = await this.userRepository.findOrCreate(dto.deviceToken);
await this.folderRepository.createOne(
user.id,
DEFAULT_FOLDER_NAME,
FolderType.DEFAULT,
);
}

// JWT Token Payload
const tokenPayload: JwtPayload = {
id: user.id,
};
// JWT Token 발급
const token = await this.authService.issueAccessToken(tokenPayload);

return {
userId: user.id,
token: token,
};
}
}