Velog 중간점검

공부는 혼자하는 거·2021년 6월 29일
0

velog 만들기

목록 보기
2/2

velog 프로젝트를 시작한 지 한달 반 정도 지났다..
중간중간 react와 자바스크립트를 새로 공부하면서 시작하다보니 생각보다 진행이 굉장히 더디게 진행되었다.
스스로에게 부족한 점이 넘친다는 걸 깨달은 하루 하루였다..
그래도 혼자서 벡엔드와 프론트엔드를 작업하면서 어느정도 현재 웹 생태계 트렌드에 대한 개념이 잡힌 것 같아서.. 아주 실망스럽지는 않다.
아직은 미완성이고 생각했던 목표치에는 많이많이 미달되지만.. 이쯤하고 다른 공부를 진행하는 게 낫다고 판단한다.

해놓은 게 아까우니 중간점검이라도 기록해놓자.

https://github.com/stella6767/velog

https://www.youtube.com/watch?v=szo5bsBvdds&ab_channel=%EC%86%8C%EC%86%8C%ED%95%9C%EC%B7%A8%EB%AF%B8

게시글 삭제, 게시글 수정, 댓글 삭제, 수정, 프로필 설정 기능, 회원 탈퇴 등등..은 구현하지 않았다. 귀찮기도 하고.. 딱히 구현할 생각도 없었고..

사용한 기술스택은 대강 다음과 같다.. 벡엔드는..


    implementation group: 'org.jsoup', name: 'jsoup', version: '1.13.1'

    // jwt 관련 의존성
    compile group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.2'
    runtime group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.2'
    runtime group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.2'

    implementation 'org.springframework.boot:spring-boot-starter-data-redis'


    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-web-services'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'mysql:mysql-connector-java'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'

프론트엔드는..

  "dependencies": {
    "antd": "^4.15.5",
    "axios": "^0.21.1",
    "faker": "^5.5.3",
    "immer": "^9.0.2",
    "moment": "^2.29.1",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-google-login": "^5.2.2",
    "react-icons": "^4.2.0",
    "react-quill": "^1.3.5",
    "react-redux": "^7.2.4",
    "react-refresh": "^0.8.3",
    "react-router-dom": "^5.2.0",
    "redux": "^4.1.0",
    "redux-actions": "^2.6.5",
    "redux-devtools-extension": "^2.13.9",
    "redux-saga": "^1.1.3",
    "shortid": "^2.2.16",
    "styled-components": "^5.3.0",
  },

eject를 하니 뭐 이상한 의존성들이 다 보이더라.. 실제로 사용한 패키지들은 대충 위와 같다.

소정의 성과

프로젝트를 진행하면서, 가장 큰 성과는 JWT를 통한 백엔드 서버와 프론트 서버간의 인증처리 방식에 대한 이해이다. 처음에 이걸로 개삽질을 많이 했는데 막상 하고나니 어느정도 개념이 잡혔다.

원래는 accessToken만 백엔드 서버에서 발급하고 이를 프론트 서버가 localstorage에 보관하고 인증수단으로 사용하기로 했다. 그런데 도중 refreshToken 개념을 알게되었고 이를 적용하기 위해 노력했다. 아래 이미지를 많이 참고하려고 노력했다.

벨로그에 떠도는 여러가지 코드와 글을 많이 참고했다. 원래는 벡서버가 refreshToken과 accessToken을 같이 발급, 벡서버는 refreshToken은 redis에 저장시키고 프론트는 두가지 모두를 localstorage에 저장. 프론트가 벡엔드에 인증이 필요한 주소로 요청을 보냈을 시, 벡엔드는 accessToken이 만료가 될 시, 만료되었다는 신호를 프론트에게 전달, 프론트는 그럼 refresh token을 들고 가서, 백엔드 서버에 다시 accessToken을 발급하라고 요청, 백엔드는 refreshToken을 검증하고, redis의 데이터와 비교하여, 다시 새로운 accessToken을 만들고 프론트에게 응답시키도록 했다. 이 과정에서 시큐리티 설정에서 web.ignore과 permit의 차이점을 몰라서 고생좀 했다. 내 딴에는 허용해주었다고 생각하는데, 계속해서 시큐리티 필터를 타게 되서..

그러다가 Cookie로 발급하는 것이 훨씬 간편하다는 것을 알게 되었다. 재발급 요청을 프론트단에서 한 번 더 할 필요없이 두개 다 Cookie로 발급시키면, 프론트에서는 자동으로 백서버에 요청을 할 때 두개 다 들고 간다. 그럼 백서버에서 바로 Cookie의 만료시간을 체크해서 만료되었다면 refreshToken을 체크해서 한 번에 accessToken을 발급 시키면 되는 것이다. 그래서 다시 Token을 Cookie로 변환시켜주는 작업을 했다. 쿠키로 변환시키면 자동으로 프론트가 백에 요청을 할 시 들고 가며, 이를 서버에서 인증처리를 하도록 구현했다.

자세한 구현삽질과정은 시간남으면 정리해서 올리도록 하겠다. 암튼 쿠키로 바꾸고 발급할 때, 도메인이 다르면, sameSite 정책때문에 프론트에서 쿠키가 정상적으로 저장이 안 되는 것 같다. 그래서 프론트 단에서 package.json에서 프록시 설정을 하였고, (프록시 포워드 방식? 인가..) 이로 인해 백엔드에서의 Cors 필터가 의미가 없어졌지만 일단 소스코드 상 구현은 해놨고.. 쿠키일 시 httponly를 true로 하면, JS에서 쿠키를 건드릴 수 없으므로, 그렇게 되면 만약 개발모드일 때, 브라우저에 쿠키가 남아있으면 내가 만든 jwt필터를 타게 되므로, 회원가입시 쓸데없이 필터를 타서, 가입을 못하는 문제가 생기므로 false로 설정해주었고. (회원가입 요청시 리액트에서 쿠키를 지우게끔..)

소셜로그인 같은 경우는 react-goole 패키지를 사용, Client Credentails Grant Type 방식을 사용했다. 벡서버가 Oauth 서버에 클라이언트를 담당하는 게 아닌 프론트서버가 자체적으로 구글 Oath2.0 서버에서 사용자 정보와 Token을 발급바도 이를 벡엔드에 전달, 벡엔드는 그 정보들을 가지고, 다시 자기 데이터베이스에 저장시키고, 쿠키들을 발급시키는 식이다. 이게 가장 간편하더라..

React Hooks 와 Redux-saga

React Hooks 와 Redux-saga에 대해서도 미약하게나마 더 이해를 하게 되었다. 클래스 컴포넌트 방식을 건너뛰고 공부한 문제로.. 컴포넌트 라이프 싸이클을 알았다면 해결했을 문제를 돌아돌아 해결해결하게 되었다.

문제는 useEffect의 요상한 작동방식 때문인데.. 나는 useEffect desp에 상태를 넣어주면 이 상태만 변경될 시 발동될 거라고 생각하고, 무지성으로 프로젝트를 진행하다 시간을 오래 소모했다. 알고보니 useEffect는 복합적인 상황에서 발생하므로, 컴포넌트가 리랜더링 될 때, 무적권 한 번씩 수행하게 되더라. 그래서 componentDidUpate에서만 실행시키게 하려면 따로 커스텀 훅스를 작성해서 적용해야 한다.

이 라이프싸이클이란게 안드로이드에서의 액티비티 라이프싸이클과 비슷하기도 하고.. 여러모로 재밌는 점 같다.

Redux Saga에 대해서도 많이 배울 수 있었다. 확실히 요런 거 배울수록 자바스크립트가 참 좋은 점이, 자바에서는 블락킹 걸리는 작업을 피하기 위해 쓰레드로 비동기 요청을 할시, 리턴을 받지 못해서 매번 인터페이스 콜백패턴을 작성해줘야 되는 문제가 있는데, 자바스크립트는 이러한 async await가 내장된 패키지를 활용해서 비동기 요청의 결과를 받을 수도 있고, 그 와중에서 블락킹도 안 걸리고..

소감

아쉬운 점은 무한계층형 댓글을 구현하고 싶었는데, 1계층만 만들었다.. 머리가 딸려서인지 잘 생각이 떠오르지 않더라.. SSR이나 코드 스플리팅, 커스텀웹팩 같은 것도 욕심이 났지만.. 공부하다가 힘이 부쳤고.. Docker로 배포도 해보고 싶지만 그만 두기로 했다. 테스트 코드도 작성 안 했고, 태그 기능도 만들다가 말았다. 이미지 썸네일 추출 같은 경우, 무지성으로 퀼 에디터에 base64로 인코딩 된 값을 mysql에 때려박았는데.. AWS S3 활용해서 이미지 리사이징 하고 url만 받도록 하고 싶은데.. 포기했다.

순수하게 React + Springboot 기반으로 SSR을 구현하는 것은 도대체 어떤 식으로 하는 지 감도 안 잡힌다. next.js같은 경우 개발할 때 너무너무 느리더라~~ 내 컴터가 꾸진 건지는 모르지만, vscode가 너무 작동을 안 해서 뭐가 문제인지는 좀 파악을 해봐야될 것 같다.

그리고 JPA 양방향 맵핑 할 시, lazyloading 이슈를 해결하고 싶은데, 걍 편하게 Entity를 리턴시키고 싶은데, 할 때마다. lazyloading 에러가 뜨드라. lazyloading을 유지하면서, 고대로 엔티티를 리턴시키는 방법이 없는지 검색을 많이 했지만, 딱히 해결책이 없다. 그냥 직렬화 안 시키게 아예 igonre 시키면, 내가 생각한 기능을 구현할 수 없고. 결국 해결책은 각각 DTO 를 만들어서 리턴시키는 건데.. 그게 싫어서 검색을 오지게 했지만.. 방법이 없다.. 기본기가 없으니까 어떻게 해결해야할지 감도 안 잡히고..

보안이나 XSS CSRF 공격같은 것도 전혀 신경쓰지 못했다.

CSS는 할 때마다 느끼지만, 쉬운 것 같으면서도 어렵다. 그리고 재미없기도 하고..

앞으로 스프링 레거시와 Mybatis를 좀 더 파봐야겠다..

profile
시간대비효율

0개의 댓글