첫번쨰 스프링 프로젝트를 좀 더 디벨롭시키는 두번째 프로젝트가 생각보다 어려워서 오랜만에 TIL을 쓰게 되었다. 아직 갈길이 멀지만 두번째 프로젝트 과제를 완료하게 되어 뿌듯한 마음이 들었다. 이번 프로젝트에서는 새롭게 배운 내용과 프로젝트에 구현한 기능들은 다음과 같다.
Spring Security에 대한 이해
Spring Security를 활용한 로그인 / 회원가입 구현
백엔드 / 프론트엔드에서 회원가입 시 유효성 검사
카카오 소셜 로그인 기능 구현
JUnit/Mockito를 활용한 유닛 테스트
24시간마다 리셋되는 블로그 공유 웹사이트
WebsiteURL: http://ksbfirst.shop
Github Link: https://github.com/SeongBeomKo/myblog
backend
Java, Spring Boot
MySQL, AWS RDS/EC2
Frontend
Html/css
Javascript
최소 3자 이상, 알파벳 대소문자(a~z, A~Z), 숫자(0~9)
로 구성하기최소 4자 이상이며, 닉네임과 같은 값이 포함된 경우 회원가입에 실패
로 만들기로그인 페이지
로 이동시키기전체 게시글 목록 조회 페이지
로 이동시키기아래 페이지를 제외하고
모두 로그인 한 경우만 볼 수 있도록 하기로그인 페이지
로 이동시키기전체 게시글 목록 조회 페이지
로 이동시키기로그인 페이지
로 이동시키기최소 3자 이상, 알파벳 대소문자(a~z, A~Z), 숫자(0~9)
로 이루어져 있어야 합니다.최소 4자 이상이며, 닉네임과 같은 값이 포함된 경우 회원가입에 실패
합니다.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 서버 에러를 유발시킬수도 있다.
백엔드에서만 검사할 경우: 벡엔드에 검증 코드를 작성한 후에, 응답 결과에 따라 프론트엔드에서는 메세지만 노출하는 방식인데, 매번 서버에 유효성 요청을 하니 서버 입장에서는 비효율적으로 많은 요청이 오게 되고 사용자는 서버의 부하로 반응속도 차이를 경험할 수 밖에 없다.
설계 → 개발 → 테스트 →설계 수정 순서를 설계 → 테스트(설계 수정) → 개발 순서로 변경하여 진행하는 개발 방식이다.
짧은 개발 주기의 반복에 의존하는 개발 프로세스이며 애자일 방법론 중 하나인
eXtream Programming(XP)의 'Test-First개념에 기반을 둔 단순한 설계를 중요시한다.
일반적인 개발 방식인 '요구사항 분석 -> 설계 -> 개발 -> 테스트 -> 배포'의 형태의 개발 주기는 소프트웨어 개발을 느리게 하는 잠재적 위험 요소가 존재 할 수 있다. 그 이유로는,
결론적으로 이 방식으로 개발을 하게되면 코드의 재사용 및 유지보수가 어려워질 확률이 매우 높으므로 현재는 현업에서 많은 개발팀들이 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를 불러오는 부분을 없애서 좀 더 효율화 하였습니다.
회원이 아닌 방문자들은 게시, 수정, 삭제를 할수 없게 jquery로 일단 프론트엔드에서 request를 할 수 없도록 막아놨고,
회원 아이디 인증을 통해 수정 삭제 버튼은 회원만 볼 수 있게 브라우저 단에서 처리를 해놓았다. 하지만 api로 접근을 하는것에 대해서는 서버에서 막아놓지 않았기 때문에 보안적으로 api가 취약하다고 할 수 있다. Delete, post, put API에 인증을 거치는 부분과 에러가 발생할 경우 화면에 에러 메세지를 띄워 줌으로 서버 에러를 뱉지 않도록 개선을 해주어야 할것 같다.
<script>alert('메롱')</script>
위와 같은 간단한 xss 공격은 견딜 수 있게 필터를 적용시켜 보았습니다.
스프링 시큐리티를 배우고 기본적인 restAPI의 CRUD를 적용시켜서 웹사이트를 좀 더 향상 시켜보았는데 JWT, 통합테스트, 그리고 JPA부분에 대해 더욱더 많은 공부가 필요하고 다음주까지 최대한 역량을 끌어올려 놓고 협업 프로젝트에 참여할 수 있도록 노력해야 겠다고 생각이 들었다. 프론트엔드에서의 타임리프 템플릿 엔진 사용과 유용한 Jquery/css 사용법도 많이 익힐 수 있게 사용한 것들은 정리를 해놓아야겠다. 솔직히 템플릿을 썻음에도 화면만드는게 더 오래 걸렸다...