1번째 수정..
This commit is contained in:
parent
ca7d09b4c2
commit
3c9cba1e86
4
.env
4
.env
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
DATABASE_URL="mysql://root:@localhost:3306/test"
|
DATABASE_URL="mysql://root:@localhost:3306/test"
|
||||||
JWT_SECURITY_KEY = "security_key"
|
JWT_SECURITY_KEY = "security_key"
|
||||||
JWT_EXPIRE_MAX = "60s"
|
JWT_EXPIRE_MAX = "600s"
|
||||||
|
AUTH_USERNAME_FIELD="email"
|
||||||
|
|
||||||
DEFAULT_TABLE_PER_PAGE = 20
|
DEFAULT_TABLE_PER_PAGE = 20
|
||||||
DEFAULT_TABLE_PAGE = 0
|
DEFAULT_TABLE_PAGE = 0
|
||||||
|
|||||||
@ -27,6 +27,7 @@ export class AuthController {
|
|||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get('islogin')
|
@Get('islogin')
|
||||||
getProfile(@Request() req) {
|
getProfile(@Request() req) {
|
||||||
|
//console.log(req)
|
||||||
return req.user
|
return req.user
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,18 +15,21 @@ export class AuthService {
|
|||||||
if (user && user.password === password) {
|
if (user && user.password === password) {
|
||||||
const { password, ...result } = user
|
const { password, ...result } = user
|
||||||
// result는 password 를 제외한 user의 모든 정보를 포함한다.
|
// result는 password 를 제외한 user의 모든 정보를 포함한다.
|
||||||
|
//console.log(result)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
async login(user: any) {
|
async login(user: any) {
|
||||||
|
//console.log(user)
|
||||||
const payload = {
|
const payload = {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
name: user.name,
|
name: user.name,
|
||||||
role: user.role
|
roles: [user.role]
|
||||||
}
|
}
|
||||||
|
// console.log(payload)
|
||||||
return { access_token: this.jwtService.sign(payload) }
|
return { access_token: this.jwtService.sign(payload) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
src/auth/decorators/has-roles.decorator.ts
Normal file
4
src/auth/decorators/has-roles.decorator.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { SetMetadata } from '@nestjs/common'
|
||||||
|
import { Role } from '../guards/role.enum'
|
||||||
|
|
||||||
|
export const HasRoles = (...roles: Role[]) => SetMetadata('has-roles', roles)
|
||||||
@ -18,7 +18,7 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
|
|||||||
id: payload.id,
|
id: payload.id,
|
||||||
email: payload.email,
|
email: payload.email,
|
||||||
name: payload.name,
|
name: payload.name,
|
||||||
role: payload.role
|
roles: payload.roles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,13 +2,14 @@ import { Strategy } from 'passport-local'
|
|||||||
import { PassportStrategy } from '@nestjs/passport'
|
import { PassportStrategy } from '@nestjs/passport'
|
||||||
import { Injectable, UnauthorizedException } from '@nestjs/common'
|
import { Injectable, UnauthorizedException } from '@nestjs/common'
|
||||||
import { AuthService } from 'src/auth/auth.service'
|
import { AuthService } from 'src/auth/auth.service'
|
||||||
|
import { env } from 'process'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LocalStrategy extends PassportStrategy(Strategy) {
|
export class LocalStrategy extends PassportStrategy(Strategy) {
|
||||||
constructor(private authService: AuthService) {
|
constructor(private authService: AuthService) {
|
||||||
//super()
|
//super()
|
||||||
//If you want to check user authenticate with custom column like 'email', try pass it.
|
//If you want to check user authenticate with custom column like 'email', try pass it.
|
||||||
super({ usernameField: 'email' })
|
super({ usernameField: env.AUTH_USERNAME_FIELD })
|
||||||
}
|
}
|
||||||
|
|
||||||
async validate(email: string, password: string): Promise<any> {
|
async validate(email: string, password: string): Promise<any> {
|
||||||
|
|||||||
4
src/auth/guards/role.enum.ts
Normal file
4
src/auth/guards/role.enum.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export enum Role {
|
||||||
|
USER = 'USER',
|
||||||
|
ADMIN = 'ADMIN'
|
||||||
|
}
|
||||||
7
src/auth/guards/roles.guard.spec.ts
Normal file
7
src/auth/guards/roles.guard.spec.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { RolesGuard } from './roles.guard';
|
||||||
|
|
||||||
|
describe('RolesGuard', () => {
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(new RolesGuard()).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
27
src/auth/guards/roles.guard.ts
Normal file
27
src/auth/guards/roles.guard.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'
|
||||||
|
import { Reflector } from '@nestjs/core'
|
||||||
|
import { Observable } from 'rxjs'
|
||||||
|
import { Role } from './role.enum'
|
||||||
|
|
||||||
|
//참고: https://shpota.com/2022/07/16/role-based-authorization-with-jwt-using-nestjs.html
|
||||||
|
@Injectable()
|
||||||
|
export class RolesGuard implements CanActivate {
|
||||||
|
constructor(private reflector: Reflector) {}
|
||||||
|
|
||||||
|
canActivate(
|
||||||
|
context: ExecutionContext
|
||||||
|
): boolean | Promise<boolean> | Observable<boolean> {
|
||||||
|
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(
|
||||||
|
'has-roles',
|
||||||
|
[context.getHandler(), context.getClass()]
|
||||||
|
)
|
||||||
|
if (!requiredRoles) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
const { user } = context.switchToHttp().getRequest()
|
||||||
|
//console.log(requiredRoles)
|
||||||
|
//console.log(user)
|
||||||
|
return requiredRoles.some((role) => user?.roles?.includes(role))
|
||||||
|
//return true
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,10 +6,15 @@ import {
|
|||||||
Param,
|
Param,
|
||||||
Post,
|
Post,
|
||||||
Put,
|
Put,
|
||||||
Query
|
Query,
|
||||||
|
UseGuards
|
||||||
} from '@nestjs/common'
|
} from '@nestjs/common'
|
||||||
import { Todo } from '@prisma/client'
|
import { Todo } from '@prisma/client'
|
||||||
import { env } from 'process'
|
import { env } from 'process'
|
||||||
|
import { HasRoles } from 'src/auth/decorators/has-roles.decorator'
|
||||||
|
import { JwtAuthGuard } from 'src/auth/guards/jwt.authguard'
|
||||||
|
import { Role } from 'src/auth/guards/role.enum'
|
||||||
|
import { RolesGuard } from 'src/auth/guards/roles.guard'
|
||||||
import { TodoDTO } from './dtos/todo.dto'
|
import { TodoDTO } from './dtos/todo.dto'
|
||||||
import { TodoService } from './todo.service'
|
import { TodoService } from './todo.service'
|
||||||
|
|
||||||
@ -47,21 +52,29 @@ export class TodoController {
|
|||||||
return this.todoService.fetchAll(sql)
|
return this.todoService.fetchAll(sql)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@HasRoles(Role.USER)
|
||||||
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||||
@Get(':id')
|
@Get(':id')
|
||||||
async fetchOne(@Param('id') id: number): Promise<Todo | undefined> {
|
async fetchOne(@Param('id') id: number): Promise<Todo | undefined> {
|
||||||
return this.todoService.fetchOne(id)
|
return this.todoService.fetchOne(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@HasRoles(Role.USER)
|
||||||
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||||
@Delete(':id')
|
@Delete(':id')
|
||||||
async delete(@Param('id') id: number): Promise<Todo | undefined> {
|
async delete(@Param('id') id: number): Promise<Todo | undefined> {
|
||||||
return this.todoService.remove(id)
|
return this.todoService.remove(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@HasRoles(Role.USER)
|
||||||
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||||
@Post()
|
@Post()
|
||||||
async add(@Body() data: Todo): Promise<Todo> {
|
async add(@Body() data: Todo): Promise<Todo> {
|
||||||
return this.todoService.add(data)
|
return this.todoService.add(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@HasRoles(Role.USER)
|
||||||
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||||
@Put(':id')
|
@Put(':id')
|
||||||
async update(@Param('id') id: number, @Body() data: TodoDTO): Promise<Todo> {
|
async update(@Param('id') id: number, @Body() data: TodoDTO): Promise<Todo> {
|
||||||
return this.todoService.update(id, data)
|
return this.todoService.update(id, data)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user