diff --git a/.env b/.env index 706f5a9..3206523 100644 --- a/.env +++ b/.env @@ -18,8 +18,7 @@ JWT_CONSTANTS_ACCESS_SECRET = "access_key" JWT_CONSTANTS_ACCESS_EXPIRESIN ="60s" JWT_CONSTANTS_REFRESH_SECRET = "refresh_key" -JWT_CONSTANTS_REPRESH_EXPIRESIN ="1d" -JWT_CONSTANTS_REPRESH_SALTORROUNDS=10 +JWT_CONSTANTS_REFRESH_EXPIRESIN ="1d" DEFAULT_TABLE_PERPAGE = 10 DEFAULT_TABLE_PAGE = 1 \ No newline at end of file diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 3bc1617..18ff5eb 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -2,7 +2,8 @@ import { Body, Controller, Get, Post, UseGuards, Request } from '@nestjs/common' import { UserDTO } from 'src/user/dtos/user.dto' import { AuthService } from './auth.service' -import { JwtAuthGuard } from './guards/jwt.auth.guard' +import { JwtAccessTokenGuard } from './guards/jwt.accesstoken.guard' +import { JwtRefreshTokenGuard } from './guards/jwt.refreshtoken.guard' import { LocalAuthGuard } from './guards/local.auth.guard' @Controller('auth') @@ -17,12 +18,19 @@ export class AuthController { } //jwt.strategy의 validate에서 true인경우 넘어옴 - @UseGuards(JwtAuthGuard) + @UseGuards(JwtAccessTokenGuard) @Get('profile') - async getProfile(@Request() req) { + async profile(@Request() req) { return req.user } + //jwt.strategy의 validate에서 true인경우 넘어옴 + @UseGuards(JwtRefreshTokenGuard) + @Get('reload') + async reload(@Request() req) { + return await this.authService.reload(req.user) + } + //사용자 등록 @Post('register') async add(@Body() data: UserDTO) { diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index 58f66e0..c239e7c 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -8,7 +8,8 @@ import { AuthService } from './auth.service' import { JwtModule } from '@nestjs/jwt' import { AuthController } from './auth.controller' import { LocalStrategy } from './guards/local.strategy' -import { JwtAuthStrategy } from './guards/jwt.auth.stragy' +import { JwtAccessTokenStrategy } from './guards/jwt.accesstoken.stragy' +import { JwtRefreshTokenStrategy } from './guards/jwt.refreshtoken.stragy' import { UsersModule } from '../user/user.module' import { jwtConstants } from './guards/jwt.constants' @@ -22,7 +23,12 @@ import { jwtConstants } from './guards/jwt.constants' }) ], controllers: [AuthController], - providers: [AuthService, LocalStrategy, JwtAuthStrategy], + providers: [ + AuthService, + LocalStrategy, + JwtAccessTokenStrategy, + JwtRefreshTokenStrategy + ], exports: [AuthService] }) export class AuthModule {} diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index d3bae1c..9a1a370 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -39,7 +39,7 @@ export class AuthService { } async register(data: UserDTO): Promise { - data.refresh_token = await this.getRefreshToken() + data.refresh_token = await this.getRefreshToken(data) data.password = await this.getEcryptedPassword(data.password) return await this.login(await this.userService.add(data)) } @@ -78,9 +78,12 @@ export class AuthService { expiresIn: jwtConstants.access_expiresIn } } - async getRefreshToken(): Promise { + async getRefreshToken(data: UserDTO): Promise { const token = await this.jwtService.sign( - {}, + { + email: data.email, + name: data.name + }, { secret: jwtConstants.access_secret, expiresIn: jwtConstants.refresh_expiresIn @@ -94,7 +97,7 @@ export class AuthService { async getTokens(data: UserDTO): Promise { return { access_token: await this.getAccessToken(data), - refresh_token: await this.getRefreshToken() + refresh_token: await this.getRefreshToken(data) } } } diff --git a/src/auth/guards/jwt.auth.guard.ts b/src/auth/guards/jwt.accesstoken.guard.ts similarity index 91% rename from src/auth/guards/jwt.auth.guard.ts rename to src/auth/guards/jwt.accesstoken.guard.ts index dd5e4c9..89f99f7 100644 --- a/src/auth/guards/jwt.auth.guard.ts +++ b/src/auth/guards/jwt.accesstoken.guard.ts @@ -7,7 +7,7 @@ import { AuthGuard } from '@nestjs/passport' import { Observable } from 'rxjs' @Injectable() -export class JwtAuthGuard extends AuthGuard('jwt') { +export class JwtAccessTokenGuard extends AuthGuard('accesstoken') { canActivate( context: ExecutionContext ): boolean | Promise | Observable { diff --git a/src/auth/guards/jwt.auth.stragy.ts b/src/auth/guards/jwt.accesstoken.stragy.ts similarity index 80% rename from src/auth/guards/jwt.auth.stragy.ts rename to src/auth/guards/jwt.accesstoken.stragy.ts index 78ee72c..05e07bb 100644 --- a/src/auth/guards/jwt.auth.stragy.ts +++ b/src/auth/guards/jwt.accesstoken.stragy.ts @@ -4,13 +4,16 @@ import { Injectable, UnauthorizedException } from '@nestjs/common' import { jwtConstants } from './jwt.constants' import { AuthService } from '../auth.service' -type jwtPayloadType = { +type jwtPayloadAccessToken = { email: string name: string } @Injectable() -export class JwtAuthStrategy extends PassportStrategy(Strategy, 'jwt') { +export class JwtAccessTokenStrategy extends PassportStrategy( + Strategy, + 'accesstoken' +) { constructor(private authService: AuthService) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), @@ -20,7 +23,7 @@ export class JwtAuthStrategy extends PassportStrategy(Strategy, 'jwt') { } //AccessToken 인증 - async validate(payload: jwtPayloadType) { + async validate(payload: jwtPayloadAccessToken) { try { return await this.authService.validateUser({ email: payload.email, diff --git a/src/auth/guards/jwt.constants.ts b/src/auth/guards/jwt.constants.ts index 5b6ebc3..3a04a25 100644 --- a/src/auth/guards/jwt.constants.ts +++ b/src/auth/guards/jwt.constants.ts @@ -1,7 +1,7 @@ export const jwtConstants = { access_secret: process.env.JWT_CONSTANTS_ACCESS_SECRET, access_expiresIn: process.env.JWT_CONSTANTS_ACCESS_EXPIRESIN, - refresh_secret: process.env.JWT_CONSTANTS_REPRESH_SECRET, - refresh_expiresIn: process.env.JWT_CONSTANTS_REPRESH_EXPIRESIN, + refresh_secret: process.env.JWT_CONSTANTS_REFRESH_SECRET, + refresh_expiresIn: process.env.JWT_CONSTANTS_REFRESH_EXPIRESIN, password_saltorRounds: process.env.AUTH_PASSWORD_SALTORROUNDS } diff --git a/src/auth/guards/jwt.refreshtoken.guard.ts b/src/auth/guards/jwt.refreshtoken.guard.ts new file mode 100644 index 0000000..dc3ac70 --- /dev/null +++ b/src/auth/guards/jwt.refreshtoken.guard.ts @@ -0,0 +1,27 @@ +import { + ExecutionContext, + Injectable, + UnauthorizedException +} from '@nestjs/common' +import { AuthGuard } from '@nestjs/passport' +import { Observable } from 'rxjs' + +@Injectable() +export class JwtRefreshTokenGuard extends AuthGuard('refreshtoken') { + canActivate( + context: ExecutionContext + ): boolean | Promise | Observable { + // Add your custom authentication logic here + // for example, call super.logIn(request) to establish a session. + return super.canActivate(context) + } + + handleRequest(err, user, info) { + // You can throw an exception based on either "info" or "err" arguments + if (err || !user) { + throw err || new UnauthorizedException() + } + console.log('JwtRefreshTokenGuard.handleRequest().info =>' + info) + return user + } +} diff --git a/src/auth/guards/jwt.refreshtoken.stragy.ts b/src/auth/guards/jwt.refreshtoken.stragy.ts new file mode 100644 index 0000000..90f08f2 --- /dev/null +++ b/src/auth/guards/jwt.refreshtoken.stragy.ts @@ -0,0 +1,36 @@ +import { ExtractJwt, Strategy } from 'passport-jwt' +import { PassportStrategy } from '@nestjs/passport' +import { Injectable, UnauthorizedException } from '@nestjs/common' +import { jwtConstants } from './jwt.constants' +import { AuthService } from '../auth.service' + +type jwtPayloadRefreshToken = { + email: string + name: string +} + +@Injectable() +export class JwtRefreshTokenStrategy extends PassportStrategy( + Strategy, + 'refreshtoken' +) { + constructor(private authService: AuthService) { + super({ + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + ignoreExpiration: false, + secretOrKey: jwtConstants.refresh_secret + }) + } + + //AccessToken 인증 + async validate(payload: jwtPayloadRefreshToken) { + try { + return await this.authService.validateUser({ + email: payload.email, + name: payload.name + }) + } catch (e) { + throw new UnauthorizedException(e) + } + } +} diff --git a/src/user/user.controller.ts b/src/user/user.controller.ts index a9dccaf..6b5c478 100644 --- a/src/user/user.controller.ts +++ b/src/user/user.controller.ts @@ -14,7 +14,7 @@ import { User } from '@prisma/client' import { UserDTO } from './dtos/user.dto' import { UserService } from './user.service' import { Roles } from '../auth/decorators/roles.decorator' -import { JwtAuthGuard } from '../auth/guards/jwt.auth.guard' +import { JwtAccessTokenGuard } from '../auth/guards/jwt.accesstoken.guard' import { RolesGuard } from '../auth/guards/roles.guard' import { ROLE } from '@prisma/client' @@ -23,7 +23,7 @@ export class UserController { constructor(private readonly userService: UserService) {} @Roles(ROLE.ADMIN) - @UseGuards(JwtAuthGuard, RolesGuard) + @UseGuards(JwtAccessTokenGuard, RolesGuard) @Get() async fetchAll(@Query() query) { console.log(query) @@ -130,21 +130,21 @@ export class UserController { } @Roles(ROLE.ADMIN) - @UseGuards(JwtAuthGuard, RolesGuard) + @UseGuards(JwtAccessTokenGuard, RolesGuard) @Get(':id') async fetchOne(@Param('id') id: string) { return await this.userService.fetchOne({ id: Number(id) }) } @Roles(ROLE.ADMIN) - @UseGuards(JwtAuthGuard, RolesGuard) + @UseGuards(JwtAccessTokenGuard, RolesGuard) @Post('add') async add(@Body() data: UserDTO) { return await this.userService.add(data) } @Roles(ROLE.ADMIN) - @UseGuards(JwtAuthGuard, RolesGuard) + @UseGuards(JwtAccessTokenGuard, RolesGuard) @Put(':id') async update(@Param('id') id: string, @Body() data: UserDTO) { data.updatedAt = new Date() @@ -155,7 +155,7 @@ export class UserController { } @Roles(ROLE.ADMIN) - @UseGuards(JwtAuthGuard, RolesGuard) + @UseGuards(JwtAccessTokenGuard, RolesGuard) @Delete(':id') async delete(@Param('id') id: string): Promise { return await this.userService.remove({ id: Number(id) })