MyBlog - 개발일지2 (항해99 - 26일차)

스브코·2021년 11월 27일
0
post-custom-banner

첫번쨰 스프링 프로젝트를 좀 더 디벨롭시키는 두번째 프로젝트가 생각보다 어려워서 오랜만에 TIL을 쓰게 되었다. 아직 갈길이 멀지만 두번째 프로젝트 과제를 완료하게 되어 뿌듯한 마음이 들었다. 이번 프로젝트에서는 새롭게 배운 내용과 프로젝트에 구현한 기능들은 다음과 같다.

  • Spring Security에 대한 이해

  • Spring Security를 활용한 로그인 / 회원가입 구현

  • 백엔드 / 프론트엔드에서 회원가입 시 유효성 검사

  • 카카오 소셜 로그인 기능 구현

  • JUnit/Mockito를 활용한 유닛 테스트

MyBlog 2차 개발일지

24시간마다 리셋되는 블로그 공유 웹사이트

WebsiteURL: http://ksbfirst.shop

Github Link: https://github.com/SeongBeomKo/myblog

기술스택

backend

Java, Spring Boot

MySQL, AWS RDS/EC2

Frontend

Html/css

Javascript

추가 요구사항

  1. 회원 가입 페이지
    • 회원가입 버튼을 클릭하기
    • 닉네임, 비밀번호, 비밀번호 확인을 입력하기
    • 닉네임은 최소 3자 이상, 알파벳 대소문자(a~z, A~Z), 숫자(0~9)로 구성하기
    • 비밀번호는 최소 4자 이상이며, 닉네임과 같은 값이 포함된 경우 회원가입에 실패로 만들기
    • 비밀번호 확인은 비밀번호와 정확하게 일치하기
    • 데이터베이스에 존재하는 닉네임을 입력한 채 회원가입 버튼을 누른 경우 "중복된 닉네임입니다." 라는 에러메세지를 프론트엔드에서 보여주기
    • 회원가입 버튼을 누르고 에러메세지가 발생하지 않는다면 로그인 페이지로 이동시키기
  2. 로그인 페이지
    • 로그인, 회원가입 버튼을 만들기
    • 닉네임, 비밀번호 입력란 만들기
    • 로그인 버튼을 누른 경우 닉네임과 비밀번호가 데이터베이스에 등록됐는지 확인한 뒤, 하나라도 맞지 않는 정보가 있다면 "닉네임 또는 패스워드를 확인해주세요"라는 메세지를 프론트엔드에서 보여주기
    • 로그인 버튼을 눌러서 에러 메세지가 발생하지 않는다면 전체 게시글 목록 조회 페이지로 이동시키기
  3. 로그인 검사
    • 아래 페이지를 제외하고 모두 로그인 한 경우만 볼 수 있도록 하기
      • 회원가입 페이지
      • 로그인 페이지
      • 게시글 목록 조회 페이지
      • 게시글 조회 페이지
    • 로그인을 하지 않거나 올바르지 않은 경로로 접속한 사용자가 로그인이 필요한 경로에 접속한 경우 "로그인이 필요합니다." 라는 메세지를 프론트엔드에서 띄워주고 로그인 페이지로 이동시키기
    • 로그인 한 사용자가 로그인 페이지 또는 회원가입 페이지에 접속한 경우 "이미 로그인이 되어있습니다."라는 메세지를 띄우고 전체 게시글 목록 조회 페이지로 이동시키기
  4. 소셜 로그인 기능 만들기
    • 카카오 소셜 로그인이 가능하도록 하기
  5. 게시글 조회 페이지 > 댓글 목록 조회
    • 로그인 하지 않은 사용자도 댓글 목록 조회가 가능하도록 하기
    • 현재 조회중인 게시글에 작성된 모든 댓글을 목록 형식으로 볼 수 있도록 하기
    • 댓글 목록 위에 댓글 작성란 만들기
      • 댓글 작성에 관한 기능은 5번 요구사항으로 연결하기
    • 댓글 목록 중, 내가 작성한 댓글인 경우 댓글 수정, 댓글 삭제 버튼 만들기
      • 댓글 수정 버튼을 누르면 6번 요구사항으로 연결하기
      • 댓글 삭제 버튼을 누르면 7번 요구사항으로 연결하기
    • 제일 최근 작성된 댓글을 맨 위에 띄우기
  6. 게시글 조회 페이지 > 댓글 작성
    • 로그인 한 사용자만 댓글 작성이 가능하도록 하기
    • 게시글 조회 페이지 하단에 댓글 내용을 입력할 수 있는 댓글 작성 버튼 만들기
    • 로그인 하지 않은 사용자가 댓글 작성란을 누르면 "로그인이 필요한 기능입니다." 라는 메세지를 띄우고 로그인 페이지로 이동시키기
    • 댓글 내용란을 비워둔 채 댓글 작성 버튼을 누르면 "댓글 내용을 입력해주세요" 라는 메세지를 띄우기
    • 댓글 내용을 입력하고 댓글 작성 버튼을 누른 경우 작성한 댓글을 추가하기
  7. 게시글 조회 페이지 > 댓글 수정
    • 내가 작성한 댓글만 수정 가능하도록 하기
    • 댓글 본문이 사라지고, 댓글 내용, 저장 버튼 생성하기
    • 댓글 내용에는 이전에 입력했던 댓글 내용을 기본 값으로 채우기
    • 수정할 댓글 내용은 비어 있지 않도록 하기
    • 저장 버튼을 누른 경우 기존 댓글의 내용을 새로 입력한 댓글 내용으로 바꾸기
  8. 게시글 조회 페이지 > 댓글 삭제
    • 내가 작성한 댓글만 삭제 가능하도록 하기
    • "정말로 삭제하시겠습니까?" 메세지를 띄우고, 확인/취소 버튼 중 "확인" 버튼을 누른 경우 목록에서 해당 댓글을 삭제하기
    • 취소를 누른 경우 삭제되지 않고 그대로 유지하기
  9. 회원가입 테스트 코드 작성
    • 회원가입시 구현한 아래 조건을 검사하는 테스트 코드를 작성하기
      • 닉네임은 최소 3자 이상, 알파벳 대소문자(a~z, A~Z), 숫자(0~9)로 이루어져 있어야 합니다.
      • 비밀번호는 최소 4자 이상이며, 닉네임과 같은 값이 포함된 경우 회원가입에 실패합니다.
      • 비밀번호 확인은 비밀번호와 정확하게 일치해야 합니다.
      • 데이터베이스에 존재하는 닉네임을 입력한 채 회원가입 버튼을 누른 경우 "중복된 닉네임입니다." 라는 에러메세지가 발생합니다.
    • 테스트 코드 실행 시 실제로는 데이터베이스에 연결되지 않도록 하기
    • 각 조건 별로 2개 이상의 테스트 케이스가 존재하도록 하기

API 설계

1차 개발일지에서 추가된 요구사항을 충족시키기 위해 설계되었다.

Blog Posting / 메인 페이지

Login / SignUp

Comment

기능 구현 중 고민했던 문제점

1. 방문자는 조회기능만 가능하고 회원은 본인의 게시글과 댓글만 수정 삭제가 가능해야하는 부분

방문자와 회원의 권한을 다르게 주어야 하는데 고민을 해보니 이런식으로 설계가 나왔다.

글 작성 - 회원만 가능
글 삭제 - 회원이 본인의 글만 가능
댓글 작성 - 회원만 가능
댓글 수정 - 회원이 본인의 글만 가능
댓글 삭제 - 회원이 본인의 글만 가능
글, 댓글 조회 - 방문자, 회원 모두 가능

일단 visitor 버튼을 만들어서 인증없이 메인 페이지에 들어 갈수 있게 해주었습니다.

콘트롤러에는 API를 따로 맵핑해주어서 인증없이 들어갈수 있게 해주었고요.

SecurityConfig에서 화면에 접속하자마자 게시글을 가져오는 Get API만 허용을 해주었습니다. 게시, 수정, 삭제 API는 모두 회원만 가능하니 허용해 주지 않았고, 게시글과 상세페이지 안에 있는 댓글까지는 모두 방문자가 조회가능하게 허용해 주었습니다.

2. 유효성 검사를 백엔드와 프론트엔드 중 어디서 해야하는지

회원가입 유효성 검사를 하는데 백엔드에서는 @Valid annotation과 함수를 선언하여 확인한 후 타임리프 템플릿 엔진을 이용해 프론트엔드에 뿌려줄 수 있고, 프론트엔드로 검사를 하면 Jquery를 이용해 자바스크립트로 alert를 띄워주거나 form 태그를 이용해 type을 지정해주어서도 할 수 있다는것을 알았다. 그래서 제대로 좀 더 어떤 방법이 맞는지에 대해 알아보기 위해 리서치를 해보았다.

백엔드와 프론트엔드 유효성 검사

결론: 벡엔드와 프론트엔드 양측에서 유효성 검사를 해주어야한다.

클라이언트단에서 입력받은 데이터가 서버로 전송될때 사용자의 접근성 및 데이터의 무결성을 보장하기 위해서는 유효성 검사가 필수적이다.

예시:

프론트엔드 유효성 검사 방법: javacript와 form 태그를 활용해 검사

백엔드 유효성 검사 방법: 서버에서 함수를 만들거나 Spring @Valid 사용

프론트엔드에서만 검사할 경우: 브라우저의 개발자 도구로 손쉽게 뚫린다. 검증을 하는 if문에 breakpoint 를 걸고 콘솔창에서 데이터를 수정하여 원하는 데이터로 바꾸면 된다. 서버에 요구사항에 어긋나는 데이터가 입력되거나, 500 서버 에러를 유발시킬수도 있다.

백엔드에서만 검사할 경우: 벡엔드에 검증 코드를 작성한 후에, 응답 결과에 따라 프론트엔드에서는 메세지만 노출하는 방식인데, 매번 서버에 유효성 요청을 하니 서버 입장에서는 비효율적으로 많은 요청이 오게 되고 사용자는 서버의 부하로 반응속도 차이를 경험할 수 밖에 없다.

테스트 코드 작성을 통해 느낀 TDD의 중요성

TDD 란?

설계 → 개발 → 테스트 →설계 수정 순서를 설계 → 테스트(설계 수정) → 개발 순서로 변경하여 진행하는 개발 방식이다.

짧은 개발 주기의 반복에 의존하는 개발 프로세스이며 애자일 방법론 중 하나인

eXtream Programming(XP)의 'Test-First개념에 기반을 둔 단순한 설계를 중요시한다.

일반적인 개발 방식인 '요구사항 분석 -> 설계 -> 개발 -> 테스트 -> 배포'의 형태의 개발 주기는 소프트웨어 개발을 느리게 하는 잠재적 위험 요소가 존재 할 수 있다. 그 이유로는,

  1. 소비자의 요구사항이 명확하지 않을 수 있고,
  2. 처음부터 완벽한 설계도 어려울뿐더러,
  3. 소스코드의 품질 저하 등으로,
  4. 테스트 비용이 증가 할 수 있다는 것이다.

결론적으로 이 방식으로 개발을 하게되면 코드의 재사용 및 유지보수가 어려워질 확률이 매우 높으므로 현재는 현업에서 많은 개발팀들이 TDD방식을 도입하여 더 효율적이고 안정적이게 협업하여 개발을 진행해 나가려고 하는 추세이다.

TDD의 개발 방식은 위 그림과 같다.

TDD와 일반적인 개발 방식의 가장 큰 차이점은 테스트 코드를 작성한 뒤에 실제 코드를 작성한다는 점이다. 디자인(설계) 단계에서 프로그래밍 목적을 반드시 미리 정의해야만 하고, 또 무엇을 테스트해야 할지 미리 정의(테스트 케이스 작성)해야만 한다.

결론적으로 이러한 단계로 개발 주기를 가져가면 자연스럽게 코드의 버그가 줄어들고, 소스 코드도 간결해질 뿐더러, 개발을 진행하기 전에 설계(디자인)가 최적화 되서 미리 재설계 되기 때문에 개발 시간 단축 및 개발 완료 후 설계 수정이라는 위험도를 확연히 줄일 수 있다.

테스트 코드 작성 중 프로젝트에서 리팩토링한 부분

처음 스프링으로 프로젝트를 한거라 컨트롤러, 서비스, 레퍼지토리의 동작원리와 클라이언트와의 통신 정도만 이해를 하고 기능을 구현하는데 초첨을 맞춰 코드랄 쓰다보니 코드를 좀 지저분하게 짠거 같았는데 유닛테스트를 하려고 테스트 코드를 짜보니 뭐가 잘못된지를 스스로 느낄 수 있었고, 리팩토링을 어떻게 해야되는지 조금 감을 잡을 수 있었다.

기능 구현 완료시 코드

UserService 코드

회원 가입 컨트롤러

리팩토링 후 코드

회원 가입 컨트롤러

UserService 코드

유효성 검사 클래스

최대한 분리하여 결합도를 낮추기 위해 userService는 등록만, Controller는 응답만, SignUpValidator는 유효성검사만 하게 리팩토링 해보았습니다.

백엔드 효율을 위해 바꾼점

처음에 모듈별 결합도를 낮추기 위해 comment, blog의 CRUD(get, post, put, delete) Controller로 모두 나누어 기능을 구현했는데. 기능을 구현하면서 생각해보니 Blog 포스팅마다 있는 Comment들은 Blog.id = Comment.Blogid로 매핑이 되어있어서 Blog에 의존적이라고 판단하였습니다. 그래서 comment의 GET API를 구현하지 않고 Blog의 GET API 중 하나의 포스트만 불러오는 getOneBlogAndComments API에 Comment의 GET을 같이 구현을 했습니다. 포스트의 상세 페이지로 넘어갈때 그 포스트에 종속되어있는 Comment를 모두 불러옴으로써 페이지를 이동하고 다시 GET으로 서버와 통신하여 comment를 불러오는 부분을 없애서 좀 더 효율화 하였습니다.

더 개선해야 할 점

Backend에서 게시, 수정, 삭제에 대한 유효성 처리

회원이 아닌 방문자들은 게시, 수정, 삭제를 할수 없게 jquery로 일단 프론트엔드에서 request를 할 수 없도록 막아놨고,
회원 아이디 인증을 통해 수정 삭제 버튼은 회원만 볼 수 있게 브라우저 단에서 처리를 해놓았다. 하지만 api로 접근을 하는것에 대해서는 서버에서 막아놓지 않았기 때문에 보안적으로 api가 취약하다고 할 수 있다. Delete, post, put API에 인증을 거치는 부분과 에러가 발생할 경우 화면에 에러 메세지를 띄워 줌으로 서버 에러를 뱉지 않도록 개선을 해주어야 할것 같다.

xss 필터를 통한 보안 강화

<script>alert('메롱')</script>

위와 같은 간단한 xss 공격은 견딜 수 있게 필터를 적용시켜 보았습니다.

회고

스프링 시큐리티를 배우고 기본적인 restAPI의 CRUD를 적용시켜서 웹사이트를 좀 더 향상 시켜보았는데 JWT, 통합테스트, 그리고 JPA부분에 대해 더욱더 많은 공부가 필요하고 다음주까지 최대한 역량을 끌어올려 놓고 협업 프로젝트에 참여할 수 있도록 노력해야 겠다고 생각이 들었다. 프론트엔드에서의 타임리프 템플릿 엔진 사용과 유용한 Jquery/css 사용법도 많이 익힐 수 있게 사용한 것들은 정리를 해놓아야겠다. 솔직히 템플릿을 썻음에도 화면만드는게 더 오래 걸렸다...

profile
익히는 속도가 까먹는 속도를 추월하는 그날까지...
post-custom-banner

0개의 댓글