[React] 블로그 만들기 9 - 로그아웃 구현 , posts에 회원 인증 API 적용

2022. 3. 15. 22:24·공부하기/React

다음은 책 리액트를 다루는 기술을 읽고 공부한 내용을 바탕으로 작성된 글입니다.


 

 

 

이제 마지막 회원 인증 관련 API인 로그아웃 구현이다.

이는 매우 간단한 작업으로, 쿠키를 지워주기만 하면 되었다.

 

1. 로그아웃 구현

- src/api/auth/auth.ctrl.js

/*
  POST /api/auth/logout
*/
export const logout = async (ctx) => {
  // 로그아웃
  ctx.cookies.set('access_token');
  ctx.status = 204; // No content
};

 

- Postman

로그아웃 테스팅

테스팅 결과 Set-Cookie의 access_token이 비워졌음을 확인하였다.

 


이렇게 회원 인증 시스템 작성은 끝이 났다. 

이제 기존에 구현했던 posts API에 회원 인증 시스템을 도입해보자 !

사용자가 로그인을 해야만 포스트를 작성할 수 있고, 삭제와 수정은 오직 작성자만 할 수 있도록 구현한다.

 

1. Post 스키마 수정

일단 각 포스트를 어떤 사용자가 작성했는지 알 수 있도록 기존 Post 스키마를 수정한다.

 

- src/models/post.js

import mongoose from 'mongoose';

const { Schema } = mongoose;

const PostSchema = new Schema({
  title: String,
  body: String,
  tags: [String], // 문자열로 이루어진 배열
  publishedDate: {
    type: Date,
    default: Date.now, // 현재 날짜를 기본값으로 설정
  },
  user: {
    _id: mongoose.Types.ObjectId,
    username: String,
  },
});

const Post = mongoose.model('post', PostSchema);
export default Post;

 

작성자 정보를 담을 user 필드를 추가했다.

 

이전에 생성한 포스트 데이터 (#1~#40) 들은 더이상 유효하지 않으므로 전부 삭제 처리하였다.

 

2. 로그인시에만 API 사용

 

checkLoggedIn 이라는 미들웨어를 만들어, 로그인시에만 글쓰기, 수정, 삭제가 가능하도록 구현한다.

 

- src/lib/checkLoggedIn.js

const checkLoggedIn = (ctx, next) => {
  if (!ctx.state.user) {
    ctx.status = 401; //Unauthorized
    return;
  }
  return next();
};

export default checkLoggedIn;

 

로그인 상태를 확인하고, 로그인된 경우에만 다음 미들웨어를 실행한다.

이를 posts 라우터에 적용한다.

 

- src/api/posts/index.js

import Router from 'koa-router';
import * as postsCtrl from './posts.ctrl';
import checkLoggedIn from '../../lib/checkLoggedIn';

const posts = new Router();

posts.get('/', postsCtrl.list);
posts.post('/', checkLoggedIn, postsCtrl.write);

const post = new Router(); // /api/posts/:id

post.get('/', postsCtrl.read);
post.delete('/:id', checkLoggedIn, postsCtrl.remove);
post.patch('/:id', checkLoggedIn, postsCtrl.update);
//module.exports = posts;

posts.use('/:id', postsCtrl.checkObjectId, post.routes());

export default posts;

 

3. 포스트 작성시 사용자 정보 넣기

 

이제 포스트를 작성할 때 사용자 정보를 넣어 데이터베이스에 저장하도록 구현해야한다.

 

- src/api/posts/posts.ctrl.js

/*
POST /api/posts
{
  title: "제목",
  body: "내용",
  tags: ['태그1','태그2']
}
*/
export const write = async (ctx) => {
  const schema = Joi.object().keys({
    // 객체가 다음 필드를 가지고 있음을 검증
    title: Joi.string().required(), // required가 있으면 필수항목을 의미
    body: Joi.string().required(),
    tags: Joi.array().items(Joi.string()).required(), // 문자열로 이루어진 배열임을 뜻함
  });

  // 검증하고 나서 검증 실패인 경우 에러 처리한다.
  const result = schema.validate(ctx.request.body);
  if (result.error) {
    ctx.status = 400; //Bad Request
    ctx.body = result.error;
    return;
  }

  const { title, body, tags } = ctx.request.body;
  const post = new Post({
    title,
    body,
    tags,
    /* 추가한 부분 */
    user: ctx.state.user,
 
  });

  try {
    await post.save();
    ctx.body = post;
  } catch (e) {
    ctx.throw(500, e);
  }
};

 

- Postman

포스트 작성시 사용자 정보 넣기 테스팅

 

테스팅 결과, 성공적으로 포스트에 user의 정보가 담겨 저장되는 것을 확인하였다.

 

4. 포스트 수정 및 삭제 시 권한 확인하기

 

이제 마지막으로 포스트 작성자에 한해서만 포스트를 수정/삭제가 가능하도록 구현한다.

이 작업을 미들웨어로 처리하고 싶다면 id로 포스트를 조회하는 작업 또한 미들웨어로 해주어야 한다.

따라서 기존의 checkObjectId(Id 유효성 검사 미들웨어)를 getPostById로 바꾸고, 해당 미들웨어에서 id로 포스트를 찾은 후 ctx.state에 담는다.

 

- src/api/posts/posts.ctrl.js

export const getPostById = async (ctx, next) => {
  const { id } = ctx.params;
  if (!ObjectId.isValid(id)) {
    // id의 유효성 검사
    ctx.status = 400; // Bad Request
    return;
  }

  try {
    const post = await Post.findById(id);
    // 포스트가 존재하지 않을 때
    if (!post) {
      ctx.status = 404; // Not Found
      return;
    }

    ctx.state.post = post;
    return next();
  } catch (e) {
    ctx.throw(500, e);
  }
};

 

이후 posts 라우터에도 이를 반영한다.

 

- src/api/posts/index.js

import Router from 'koa-router';
import * as postsCtrl from './posts.ctrl';
import checkLoggedIn from '../../lib/checkLoggedIn';

const posts = new Router();

posts.get('/', postsCtrl.list);
posts.post('/', checkLoggedIn, postsCtrl.write);

const post = new Router(); // /api/posts/:id

post.get('/', postsCtrl.read);
post.delete('/:id', checkLoggedIn, postsCtrl.remove);
post.patch('/:id', checkLoggedIn, postsCtrl.update);
//module.exports = posts;

posts.use('/:id', postsCtrl.getPostById, post.routes());
/* 반영된 부분 */
export default posts;

 

그 다음, read 함수 내에서 id로 포스트를 찾는 코드를 간소화해준다.

 

- src/api/posts/posts.ctrl.js

/*
GET /api/posts/:id
*/
export const read = async (ctx) => {
  ctx.body = ctx.state.post;
};

 


이제 checkOwnPost 라는 미들웨어를 만든다. 이 미들웨어가 현재 수정/삭제 하려는 포스트가 사용자 본인의 포스트인지 확인하는 역할을 할 것이다.

 

- src/api/posts/posts.ctrl.js

export const checkOwnPost = (ctx, next) => {
  const {user, post} = ctx.state;
  if( user._id !== post.user._id.toString()) {
    ctx.status = 403;
    return;
  }
  return next();
}

 

이제 이 미들웨어를 수정 및 삭제 API에 적용해주면 된다.

 

- src/api/posts/index.js

post.delete('/:id', checkLoggedIn, postsCtrl.checkOwnPost, postsCtrl.remove);
post.patch('/:id', checkLoggedIn, postsCtrl.checkOwnPost, postsCtrl.update);

 

- Postman

테스팅을 위해 username:user1 으로 회원가입 후, 포스트를 하나 생성했다.

이후 로그아웃하고, username:subbni로 로그인 한 다음 위의 포스트를 삭제하는 요청을 보내보았다.

근데 띠용 .. Method Not Allowed가 떴다.

뭐가 잘못됐나 .. 하고 코드를 확인해보던 중, 

 

- src/api/posts/index.js 에서

post.get과 post.delete의 경로를 './:id'에서 '/'로 바꾸는 것을 빼먹은 것을 확인했다.

 

- src/api/posts/index.js

import Router from 'koa-router';
import * as postsCtrl from './posts.ctrl';
import checkLoggedIn from '../../lib/checkLoggedIn';

const posts = new Router();

posts.get('/', postsCtrl.list);
posts.post('/', checkLoggedIn, postsCtrl.write);

const post = new Router(); // /api/posts/:id

post.get('/', postsCtrl.read);
post.delete('/', checkLoggedIn, postsCtrl.checkOwnPost, postsCtrl.remove);
post.patch('/', checkLoggedIn, postsCtrl.checkOwnPost, postsCtrl.update);
//module.exports = posts;

posts.use('/:id', postsCtrl.getPostById, post.routes());

export default posts;

 

 

 

수정 후 다시 요청을 보내자 성공적으로 Forbidden이 뜨는 것을 확인하였다.

 

 

저작자표시 (새창열림)

'공부하기 > React' 카테고리의 다른 글

[React] 블로그 만들기 8 - 토큰 발급 및 검증  (1) 2022.03.15
[React] 블로그 만들기 7 - 로그인 구현  (0) 2022.03.15
[React] 블로그 만들기 6 - 회원가입 구현  (1) 2022.03.15
[React] 블로그 만들기 5 - 페이지네이션 구현  (0) 2022.03.14
[React] 블로그 만들기 4 - Request Body 검증  (0) 2022.03.14
'공부하기/React' 카테고리의 다른 글
  • [React] 블로그 만들기 8 - 토큰 발급 및 검증
  • [React] 블로그 만들기 7 - 로그인 구현
  • [React] 블로그 만들기 6 - 회원가입 구현
  • [React] 블로그 만들기 5 - 페이지네이션 구현
다섯자두
다섯자두
All I need is 💻 , ☕️ and a dash of luck
  • 다섯자두
    subbni
    다섯자두
  • 전체
    오늘
    어제
    • 전체 글 (88) N
      • 개발 이야기 (0)
      • 만들어보기 (17)
        • FromBookToBook (5)
        • Spring (5)
        • Node.js & React (3)
        • TroubleShooting (4)
      • 공부하기 (71) N
        • Network (3)
        • Cloud (1)
        • Database (5)
        • Java (13)
        • Javascript (0)
        • Spring (9)
        • React (18)
        • Algorithm (8)
        • 자료구조 (7)
        • ETC (7) N
      • 회고 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • velog
  • 공지사항

  • 인기 글

  • 태그

    pdf 프리뷰 실패
    Database
    서명알고리즘
    JPA
    자료구조
    java
    실시간 데이터 전송 기술
    outbox 패턴
    pdf 자동 다운로드
    SQS
    티스토리챌린지
    aws
    최단거리
    outbox
    알림 기능
    HTTP
    network
    mysql
    Til
    redis
    SSE
    알고리즘
    springboot
    오블완
    로그인
    재시도 로직
    프로젝트
    Spring
    Express
    SQL
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
다섯자두
[React] 블로그 만들기 9 - 로그아웃 구현 , posts에 회원 인증 API 적용
상단으로

티스토리툴바