[NestJS] 접근 권한 처리 (CRUD)
원래 공식문서 보고하다가 중간에 John Ann님 강의로 틀어서 강의에서의 Board는 내 코드에서 Cat이라고 보면됨
(user : 주인, cat : 고양이 라고 생각해야지 ex.주인1만 고양이1에게 접근 가능)
✅ 유저에게 고양이 접근 권한 주기
인증 관련 모듈인 Auth module을 Cat에서 쓸 수 있어야하기 때문에 Cat module에서 Auth module을 import 해와야한다
// cats.module.ts
Module({
imports: [TypeOrmModule.forFeature([Cat]), AuthModule], // auth module 추가
exports: [TypeOrmModule],
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {}
현재 client가 cat에 접근하기에 유효한 client 인지 본 후에 권한을 줘야하기 때문에 cat controller에 모든 핸들러에 대해 Guard를 씌워주기 ! (이전 게시물에서 했던 것 처럼)
@Controller("cats")
@UseGuards(AuthGuard()) // 밑에 있는 모든 핸들러가 영향을 받는다
export class CatsController {...}
>> 올바른 토큰을 안넣으면 401 Unauthorized 에러나게됨
✅ 유저와 고양이의 관계 형성해주기
나와 내 고양이의 관계를 정립해줘야함. 고양이 정보를 넣을때도 이 고양이의 주인이 누구인지 등등 정보를 넣어줘야함.
🔽 TypeOrm의 관계 설정 방법
@OneToMany, @ManyToOne, @ManyToMany, @OneToOne
1. user-cat 엔티티간에 서로의 필드를 넣어줘야함
- 1명의 User는 여러 Cat과 관계 (1 : N)
- 여러마리 Cat이 1명의 User와 관계됨 ( N : 1 )
// user.entity.ts
@Entity("user")
@Unique(["username"])
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
username: string;
@Column()
password: string;
@OneToMany((type) => Cat, (cat) => cat.user, { eager: true })
cats: Cat;
}
- { eager : true } : User 정보 가져올 때 cat도 같이 가져옴
// cat.entity.ts
@Entity()
export class Cat {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
age: number;
@Column()
breed: string;
@ManyToOne((type) => User, (user) => user.cats, { eager: false })
user: User;
}
✅ Cat 정보 넣어줄 때 User 정보 넣어주기 (Post)
"이 cat의 주인은 어떤user다" 라는 정보도 같이 넣어줘야함
// cats.controller.ts
@Post()
create(@Body() cat: Cat, @GetUser() user: User) {
return this.catsService.create(cat, user);
}
// cats.service.ts
async create(cat: Cat, user: User): Promise<void> {
const { name, age, breed } = cat;
const catt = new Cat();
catt.age = age;
catt.breed = breed;
catt.name = name;
catt.user = user;
await this.catsRepository.save(catt);
}
// cats은 repository와 service를 따로 나누지 않았음
🔽 테스트
1. user1로 로그인 후 반환되는 토큰 복사

2. cat post request보낼때 Authorization(type: bearor Token)에 복사한 토큰 넣어주고 Body에 고양이 정보 넣어서 보내기

3. DB에 cat 테이블에 userId 라는 칼럼 새로 생기며 정보 제대로 들어간 것 확인

✅ 해당 User의 고양이만 가져오기 (Get)
내 고양이들의 정보만 조회해야할때 (약간 마이페이지 기능 구현할 때 쓸 듯?)
현재는 로그인 성공한 모든 유저는 모든 고양이 정보를 볼 수 있음
// cats.controller.ts
@Get()
findAll(@GetUser() user: User): Promise<Cat[]> {
return this.catsService.findAll(user);
}
// cats.service.ts
async findAll(user: User): Promise<Cat[]> {
const query = this.catsRepository.createQueryBuilder("cat"); // cat에 접근할것
query.where("cat.userId = :userId", { userId: user.id });
const cats = await query.getMany(); //여기서 나오는 것들 전부다 가져오라는 뜻 이 조건에 맞는 모든 cat이 들어간다
return cats;
}
🔽 테스트
1. user1로 로그인 후 토큰 복사
2. GET localhost:3000/cats 요청에 복사한 토큰 넣어서 전송
3. user1가 등록한 고양이 정보만 볼 수 있음

✅ 자신이 생성한 고양이 정보 수정하기 (Patch)
수정하고자하는 고양이의 아이디를 이용해 내가 작성한 고양이 정보만 수정
// cats.controller.ts
// age만 수정할 것
@Patch(":id")
update( @Param("id") id: number, @Body("age") age: number, @GetUser() user: User) {
this.catsService.update(id, age, user);
return `This action updates a #${id} cat`;
}
// cats.service.ts
async update(id: number, age: number, user: User): Promise<Cat> {
const cat = await this.findCatById(id, user);
cat.age = age;
await this.catsRepository.save(cat);
return cat;
}
async findCatById(id: number, user: User): Promise<Cat> {
const found = await this.catsRepository.findOne({
where: { id, userId: user.id },
});
return found;
}
✅ 자신이 생성한 고양이 정보 삭제하기 (Delete)
삭제하고자하는 고양이의 아이디를 이용해 내가 작성한 고양이 정보만 삭제
// cats.controller.ts
@Delete(":id")
remove(@Param("id") id: number, @GetUser() user: User) {
this.catsService.remove(id, user);
}
// cats.service.ts
async remove(id: number, user: User): Promise<void> {
// 해당 cat을 가진 user만이 삭제할 수 있음
await this.catsRepository.delete({ id, user });
}