Skip to content

Commit

Permalink
[feat] user api 완성, login guard 전역 설정 (#113)
Browse files Browse the repository at this point in the history
* feat: redis 값꺼내오기

* feat: login Guard

* feat: user api 완성, login guard 전역 설정

* fix: console log 삭제

* fix: 리뷰반영

* fix: 리뷰 반영

* fix: lint 적용

* fix: remove unused modules

* fix: login 후 session.userId로 확인

* fix: login Guard global setting 수정

* fix: login Guard 오류 해결

* fix: review 반영

* fix: review 반영
  • Loading branch information
jmhee28 authored Dec 4, 2023
1 parent 10eab35 commit d5700e9
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 50 deletions.
2 changes: 2 additions & 0 deletions server/api-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
},
"dependencies": {
"@nestjs/axios": "^3.0.1",
"@nestjs/cache-manager": "^2.1.1",
"@nestjs/common": "^10.0.0",
"@nestjs/config": "^3.1.1",
"@nestjs/core": "^10.0.0",
Expand Down Expand Up @@ -58,6 +59,7 @@
"@nestjs/schematics": "^10.0.0",
"@nestjs/testing": "^10.0.0",
"@types/bcrypt": "^5.0.2",
"@types/cookie-parser": "^1.4.6",
"@types/express": "^4.17.21",
"@types/express-session": "^1.17.10",
"@types/ioredis": "^5.0.0",
Expand Down
17 changes: 13 additions & 4 deletions server/api-server/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Session,
Post,
Body,
HttpException,
} from '@nestjs/common';
import { NaverAuthGuard } from './guard/naver-auth.guard';
import { AuthService } from './auth.service';
Expand Down Expand Up @@ -36,9 +37,17 @@ export class AuthController {
@Req() req,
@Res() res: Response,
): Promise<any> {
session.userId = req.user.userId;

const sessionId = session.id;
res.json({ sessionId });
session.userId = req.user.userId;
res.redirect(process.env.CLIENT_ORIGIN);
res.send(`<script>window.close();</script>`);
res.end();
}

@Get('sessionId')
async getSessionId(@Session() session: Record<string, any>) {
if (!session.id) {
throw new HttpException('Unauthorized', 401);
}
return { session: session.id };
}
}
1 change: 1 addition & 0 deletions server/api-server/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
import { UsersService } from '../users/users.service';
import { CreateUserDto } from '../users/dto/create-user.dto';
import { v4 as uuid } from 'uuid';

@Injectable()
export class AuthService {
constructor(private usersService: UsersService) {}
Expand Down
38 changes: 22 additions & 16 deletions server/api-server/src/auth/guard/logged-in.guard.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import {
CanActivate,
ExecutionContext,
Injectable,
Logger,
} from '@nestjs/common';
import { Request } from 'express';
import { Observable } from 'rxjs';

interface LoggedInSession {
cookie: any;
userId: string | undefined;
}

@Injectable()
export class LoggedInGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
private readonly logger = new Logger(LoggedInGuard.name);

async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest() as Request;
const sid = this.getSidFromCookie(request.headers.cookie);
// TODO token이 유효한지 확인하는 로직이 필요함
return sid !== null;
}
const session = request.session as unknown as LoggedInSession;
const isAuthenticated = session?.userId ? true : false;

getSidFromCookie(cookieString) {
const cookies = cookieString.split('; ').reduce((acc, cookie) => {
const [key, value] = cookie.split('=');
acc[key] = value;
return acc;
}, {});
if (isAuthenticated) {
this.logger.debug(`Authenticated: ${session?.userId}`);
} else {
this.logger.debug(`Unauthenticated`);
}

return cookies['connect.sid'];
return isAuthenticated;
}
}
9 changes: 5 additions & 4 deletions server/api-server/src/common/redis.session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import * as session from 'express-session';
import RedisStore from 'connect-redis';
import { createClient } from 'redis';
import { Logger } from '@nestjs/common';
import * as process from 'process';

export function getSession() {
const logger = new Logger(getSession.name);

const url = process.env.REDIS_URL || 'redis://localhost:6379';
const url = process.env.REDIS_URL;
const redisClient = createClient({
url,
});
Expand All @@ -21,9 +21,10 @@ export function getSession() {
saveUninitialized: false,
resave: false,
store: redisStore,
proxy: true,
cookie: {
httpOnly: false,
secure: false,
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
maxAge: 1000 * 60 * 60 * 24 * 7,
},
});
Expand Down
6 changes: 6 additions & 0 deletions server/api-server/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ import { AppModule } from './app.module';
import { getSession } from './common/redis.session';
import { RedisIoAdapter } from './common/redis.adapter';
import * as passport from 'passport';
import * as process from 'process';

async function bootstrap() {
const app = await NestFactory.create(AppModule);

app.enableCors({
origin: process.env.CLIENT_ORIGIN,
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
credentials: true,
});
const session = getSession();
app.use(session);
app.use(passport.initialize());
Expand Down
1 change: 0 additions & 1 deletion server/api-server/src/streams/streams.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { UpdateStreamDto } from './dto/update-stream.dto';
@Controller('streams')
export class StreamsController {
constructor(private readonly streamsService: StreamsService) {}

@Get()
findAll(@Query('page') page = '1', @Query('size') size = '5') {
return this.streamsService.findAll(+page, +size);
Expand Down
24 changes: 12 additions & 12 deletions server/api-server/src/users/users.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('UsersController', () => {
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [
ConfigModule.forRoot({isGlobal: true}),
ConfigModule.forRoot({ isGlobal: true }),
TypeOrmModule.forRoot({
type: 'mysql',
host: process.env.DB_HOST,
Expand All @@ -32,7 +32,7 @@ describe('UsersController', () => {
],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService, TypeOrmModule]
exports: [UsersService, TypeOrmModule],
}).compile();

controller = module.get<UsersController>(UsersController);
Expand All @@ -57,16 +57,16 @@ describe('UsersController', () => {
// Arrange
const expectedResult = [
{
"id": "3cdce141-d9de-4f7b-b95c-e42acb602167",
"userId": "ddd",
"oauthId": "iNGxLq4KTWs7A6YCAMkdj76nNbWoW2Q1CO9kPbxbOqg",
"oauthType": "naver",
"nickname": "jmh",
"createdAt": "2023-11-27T14:37:35.955Z",
"updatedAt": "2023-11-27T14:45:14.795Z",
"deletedAt": null,
"stream": null // Add the stream property here
}
id: '3cdce141-d9de-4f7b-b95c-e42acb602167',
userId: 'ddd',
oauthId: 'iNGxLq4KTWs7A6YCAMkdj76nNbWoW2Q1CO9kPbxbOqg',
oauthType: 'naver',
nickname: 'jmh',
createdAt: '2023-11-27T14:37:35.955Z',
updatedAt: '2023-11-27T14:45:14.795Z',
deletedAt: null,
stream: null, // Add the stream property here
},
];

jest.spyOn(service, 'findAll').mockResolvedValue(expectedResult);
Expand Down
18 changes: 18 additions & 0 deletions server/api-server/src/users/users.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ import {
Param,
Delete,
Req,
UseGuards,
Session,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { LoggedInGuard } from '../auth/guard/logged-in.guard';

@Controller('users')
export class UsersController {
Expand All @@ -21,6 +26,18 @@ export class UsersController {
return this.usersService.create(createUserDto);
}

@UseGuards(LoggedInGuard)
@Get('me')
async getUserBySessionId(@Session() session: Record<string, any>) {
if (!session.userId) {
throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
}

const user = await this.usersService.findOne(session.userId);

return { userId: user.userId, nickname: user.nickname };
}

@Get()
findAll() {
return this.usersService.findAll();
Expand All @@ -30,6 +47,7 @@ export class UsersController {
findOne(@Param('id') id: string) {
return this.usersService.findOne(id);
}

@Patch()
update(@Req() req, @Body() updateUserDto: UpdateUserDto) {
const id = req.session.userId;
Expand Down
7 changes: 1 addition & 6 deletions server/api-server/src/users/users.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,10 @@ import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
import { AuthModule } from '../auth/auth.module';
import { StreamsModule } from '../streams/streams.module';

@Module({
imports: [
TypeOrmModule.forFeature([User]),
forwardRef(() => AuthModule),
forwardRef(() => StreamsModule),
],
imports: [TypeOrmModule.forFeature([User]), forwardRef(() => StreamsModule)],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService, TypeOrmModule],
Expand Down
23 changes: 16 additions & 7 deletions server/api-server/src/users/users.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable } from '@nestjs/common';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { InjectRepository } from '@nestjs/typeorm';
Expand All @@ -24,8 +24,8 @@ export class UsersService {
return newUser;
}

findAll(): Promise<User[]> {
return this.userRepo.find();
async findAll() {
return await this.userRepo.find();
}

async findByOAuthId(oauthId: string) {
Expand All @@ -35,15 +35,19 @@ export class UsersService {
}

async findOne(id: string) {
return await this.userRepo.findOne({
const user = await this.userRepo.findOne({
where: { id },
});
if (!user || !id) {
throw new HttpException('User not found', HttpStatus.NOT_FOUND);
}
return user;
}

async update(id: string, updateUserDto: UpdateUserDto) {
const user = await this.findOne(id);
if (!user) {
throw new Error(`User with id: ${id} not found`);
throw new HttpException('User not found', HttpStatus.NOT_FOUND);
}

for (const key in updateUserDto) {
Expand All @@ -57,7 +61,12 @@ export class UsersService {
return updatedUser;
}

remove(id: string) {
return `This action removes a #${id} user`;
async remove(id: string) {
const result = await this.userRepo.softDelete(id);
if (!result.affected)
throw new HttpException('User not found', HttpStatus.NOT_FOUND);
else {
return result;
}
}
}
12 changes: 12 additions & 0 deletions server/api-server/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,11 @@
resolved "https://registry.npmjs.org/@nestjs/axios/-/axios-3.0.1.tgz"
integrity sha512-VlOZhAGDmOoFdsmewn8AyClAdGpKXQQaY1+3PGB+g6ceurGIdTxZgRX3VXc1T6Zs60PedWjg3A82TDOB05mrzQ==

"@nestjs/cache-manager@^2.1.1":
version "2.1.1"
resolved "https://registry.yarnpkg.com/@nestjs/cache-manager/-/cache-manager-2.1.1.tgz#abc042c6ac83400c64fd293b48ddb2dec99f6096"
integrity sha512-oYfRys4Ng0zp2HTUPNjH7gizf4vvG3PQZZ+3yGemb3xrF+p3JxDSK0cDq9NTjHzD5UmhjiyAftB9GkuL+t3r9g==

"@nestjs/cli@^10.0.0":
version "10.2.1"
resolved "https://registry.npmjs.org/@nestjs/cli/-/cli-10.2.1.tgz"
Expand Down Expand Up @@ -1030,6 +1035,13 @@
dependencies:
"@types/node" "*"

"@types/cookie-parser@^1.4.6":
version "1.4.6"
resolved "https://registry.yarnpkg.com/@types/cookie-parser/-/cookie-parser-1.4.6.tgz#002643c514cccf883a65cbe044dbdc38c0b92ade"
integrity sha512-KoooCrD56qlLskXPLGUiJxOMnv5l/8m7cQD2OxJ73NPMhuSz9PmvwRD6EpjDyKBVrdJDdQ4bQK7JFNHnNmax0w==
dependencies:
"@types/express" "*"

"@types/cookie@^0.4.1":
version "0.4.1"
resolved "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz"
Expand Down

0 comments on commit d5700e9

Please sign in to comment.