일반 스크립트(수정본)

Jingu_Jeon·2024년 10월 16일

목차
1. MVC 패턴 구조
2. 디렉토리 구조 소개 및 기능 소개
3. 기술스택 소개
4. JWT와 Web Socket기반의 1:1 채팅

PHCCS 프로젝트의 백엔드 파트 발표를 맡은 전진구입니다. 발표 시작하겠습니다.

13p
먼저 PHCCS 프로젝트의 MVC 패턴 구조에 대해 설명을 하고
서비스 구현을 위해 사용된 기술스택에 대해서 설명을 하고
핵심이 되는 서비스인 Java web token 발급, 검증 서비스 그리고 websocket을 기반으로한 1대1 채팅 서비스에 대해서 설명하겠습니다.

14p
Pet health care community service 는 REST 기반의 MVC 패턴을 따르고있습니다.

(mvc 패턴 소개)
먼저 MVC 패턴에 대해 간단히 짚고 넘어가겠습니다.
MVC는 Model-View-Controller의 약자로, 웹 애플리케이션을 크게 세 가지 역할로 나누어 설계하는 패턴입니다.
model 계층은 애플리케이션의 데이터와 비즈니스 로직을 처리합니다.
view 계층은 사용자가 볼 수 있는 화면을 렌더링 합니다.
controller 계층은 사용자의 요청을 받아 그 요청을 처리하고 적절한 데이터를 모델에서 가져와서 view에 전달합니다.

다만 저희 PHCSS 프로젝트는 REST 기반의 MVC 패턴을 따르고 있어서 View 역할은 React에서 수행됩니다.
따라서 백엔드 서버는 Model과 Controller 역할을 주로 담당합니다.

이와 같은 구조를 통해 PHCCS는 명확한 역할 분담과 유지 보수성 높은 설계를 따르고 있다고 말할 수 있겠습니다.

15p
(기술스택 소개)
*앞서 말씀드린 것 처럼 PHCCS 프로젝트는 다양한 기술스택을 활용하고 있습니다.

백엔드 프레임워크로는 Spring boot를 사용하고 있고 Spring MVC 구조로 설계되었습니다. 그리고 REST API 방식으로 클라이언트와 서버간의 데이터 를 주고 받습니다.
데이터베이스는 Mysql을 사용하고 있고, 데이터베이스와 상호 작용을 위해 MyBatis를 통해 처리됩니다.
또한 사용자 인증과 보안을 위해서 JWT을 활용하고 1대1 채팅 기능 구현을 위해서 양방향 통신 프로토콜인 WebSocket을 활용하고 있습니다.

16p
3. jwt 토큰 소개
(토큰 생성)
이제 PCCCS 프로젝트에서의 Java Web Token과 Websocket 의 적용에 대해서 설명해드리겠습니다.

(적용 설명)
먼저 JWT의 적용에 대해서 설명하겠습니다.

먼저 JWT 속성을 정의해야합니다.
해당 코드는 설정 파일인 application-jwt-properties
첫번째 줄부터 발급자, 비밀키, AccessToken의 유효시간, refreshToken의 유효시간을 정의합니다.

17
다음으로 토큰 발급의 전체적인 흐름에 대해 설명하도록 하겠습니다.
첫번째로
1. 이메일과 비밀번호 검증

클라이언트가 입력한 이메일과 비밀번호를 데이터베이스의 사용자 정보와 대조합니다.
만약 이메일이 일치하지 않으면 "회원을 찾을 수 없음" 오류를 반환하고, 비밀번호가 일치하지 않으면 "검증되지 않음" 오류를 반환합니다.

  1. Access Token 생성

사용자가 성공적으로 검증되면, jwtUtil.createAccessToken() 메서드를 호출하여 Access Token을 생성합니다.
Access Token은 사용자 ID와 역할(role)을 포함하고, 짧은 유효 기간을 가집니다.

  1. Refresh Token 생성

Access Token과 함께 Refresh Token도 생성됩니다.
Refresh Token은 사용자 ID만을 포함하고, 비교적 긴 유효 기간을 가집니다.

  1. Access Token과 Refresh Token 반환

생성된 Access Token과 Refresh Token은 클라이언트에게 반환됩니다.
이제 클라이언트는 Access Token을 사용하여 인증된 요청을 보내고, Access Token이 만료되면 Refresh Token으로 새로운 Access Token을 발급받을 수 있습니다.

18P

  1. Jwts.builder()

    왼쪽에 보이는 해당 코드 Jwts.parserBuilder 는 실제로 JWT를 생성하는 핵심 메서드입니다.
    JJWT 라이브러리에서 제공하며, JWT의 헤더(Header), 페이로드(Patload), 서명(Signature) 등을 설정하고 최종적으로 JWT 토큰을 문자열로 생성합니다.

실제 백엔드에서 토큰을 보내고 프론트에서 받은 토큰 출력한 사진입니다.
(프론트)

(백)

accesstoken: eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoxLCJqdGkiOiJjZTM2NjQ3NC00NjE1LTQ1ZmUtYTVkNC01Njk1ZDZlZjhjNGEiLCJzdWIiOiI0IiwiaXNzIjoid2xzcm4xNThAZ21haWwuY29tIiwiaWF0IjoxNzI5MDUzNzIzLCJleHAiOjE3MjkwNTQzMjN9.JebwjKRaw4TxTkWYD9Y4GAnbxnPf5qiRPXAG8TSODxs
refreshtoken:
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI1M2IxODk4My02MjFmLTRkNTYtOTgzZC1hNTM2M2JhZjkxMTEiLCJzdWIiOiI0IiwiaXNzIjoid2xzcm4xNThAZ21haWwuY29tIiwiaWF0IjoxNzI5MDUzNzIzLCJleHAiOjE3Mjk2NTg1MjN9.1wXN9CcCgkSiPJr6oWAuLhMDxik6ickMOFDR18p0qqA

19p
다음으로 토큰 인증의 전체적인 흐름에 대해 설명하겠습니다.

우선 토큰 인증을 위해서는 토큰 인증 필터를 만들어야합니다. 해당 프로젝트에는 JwtAuthenticationFilter를 만들어 Contoroller나 Service 레이어의 로직이 실행되기전에 JWT 인증 필터를 거쳐 토큰의 유효성을 검사 진행하는 방식으로 토큰 인증을 구현했습니다.

20p
JWT 인증 필터의 작동 흐름에 대해 설명하겠습니다.
첫번째로
1. 화이트 리스트 확인
클라이언트의 요청이 서버에 전달되면 JWT 인증 필터는 인증 로직을 실행하는데 실행하기에 앞서 화이트 리스트를 먼저 확인 합니다.
isLoginCheckPath() 메서드를 통해 요청 URI가 인증이 필요없는 경로인지 확인합니다.

해당 프로젝트에서 설정한것 처럼 /auth/signin, /auth/signup, /auth/refresh 등의 경로는 인증 없이 필터를 통과 시킵니다.

  1. Authorization(어써리제이션) 헤더 검증
    Authorzaiton 헤더의 JWT 토큰이 포함되어 있는지 확인합니다.
    Bearer로 시작하지 않거나 헤더가 없으면 401 오류를 반환합니다.

  2. JWT 토큰 검증
    JwtUtil.validateAccessToken() 호출하여 JWT의 유효성을 검증합니다.

  3. 요청 처리
    JWT 검증이 통과 되면 요청은 컨트롤러로 전달되고, 실패하면 즉시 401 응답을 반환합니다
    (컨트롤러로 요청을 넘기는 부분)

    (401 오류 응답 처리 부분)

21p
왼쪽 상단의 코드는 Jwts.parserBuilder JJWT라이브러리에서 제공하는 토큰을 검증하는 메서드입니다.
해당 메소드는 JWT 토큰을 파싱하고 클레임을 추출합니다.
이과정에서 토큰의 서명을 검증하는 과정이 포함됩니다.

해당 메소드에서 토큰 서명을 검증하는 과정을 설명해드리겠습니다.
우선 .setSigningkey() 에서 토큰 생성시 사용된 비밀키와 동일한 비밀키를 설정합니다.
그리고 .parseClaimsJws() 에서 실제로 JWT 토큰을 파싱하고, 서명 검증과 유효성 검증을 진행합니다.
해당 과정을 성공적으로 마치면 토큰에서 추출한 클레임을 반환하고 서명이 유효하지않거나 토큰 자체에 문제가 생겼다면 예외를 발생시킵니다.

오른쪽은 postman으로 확인한 토큰 검증 결과입니다.

JWT 토큰이 유효한 경우

헤더가 누락되거나 잘못된 경우

형식이 잘못 된 경우

22p
다음으로는 Websocket을 적용한 1대1 채팅 서비스에 대해 설명해드리겠습니다.

컨피그 클래스는 등록된 경로로 웹 소켓 요청이 오면 해당 경로에 맞는 핸들러를 확인하고 http 통신을 웹 소켓으로 업그레이드 합니다.
그 후 등록된 핸들러에게 소켓통신의 처리를 위임합니다

이제 등록된 ChatwebSocket 핸들러 클래스를 확인해 보겠습니다.

TextWebSocket핸들러를 상속받아 텍스트를 주고받는 기능을 사용할 수 있게 했습니다.
오버라이딩 메소드를 확인해보면 afterConnectionEstblished(에스테이블리쉬드)메소드는 초기 웹 소켓 연결 요청 시 처리를 해주는 매소드 입니다.
이때 웹 소켓은 session에 정보들을 담아서 통신합니다.
해당 메소드는 채팅 서비스를 사용하기 위해 채팅방에 접근하는 로직을 수행합니다 handlerTextMessage메소드는 초기 연결 이후의 데이터들을 처리하게 해주는 메소드입니다.
채팅방에 접근 후 채팅 메시지 전송하기 위한 로직을 수행합니다.
afterConnectionClosed 메소드는 웹 소켓 연결해제 이후의 로직을 수행합니다.
연결을 해제하면 채팅방에서 나가도록 합니다.

23
(사용자가 채팅을 하기 위한 과정)
사용자가 채팅을 하기 위한 과정에 대해 설명하겠습니다.

(대본으로사용) userA가 userB와 채팅을 원할경우 A는 방을 생성 후 생성된 채팅방에 입장합니다. 이때 B는 SSE를 통해 채팅방 초대 알림을 받습니다.
(대본으로사용) userA와 userB가 입장하면 채팅방에 입장 메시지를 보내줍니다.
(대본으로사용) 입장한 유저끼리 소켓을 이용한 통신을 하고 난 후 사용자가 채팅방을 떠나면 퇴장 메시지를 보내줍니다.

24
해당 프로젝트는 채팅방 초대 알림 서비스 구현을 위해 SSE를 사용했습니다.

SSE가 무엇인지 그리고 사용한 이유에 대해 추가적으로 설명해 드리겠습니다.
우선 SSE는 Server sent event의 약자로 서버에서 특정 이벤트가 발생하면 비동기적으로 데이터를 전송하는 기술입니다.

SSE를 사용하지 않았을 때는 클라이언트에서 알림이있는지 일정 주기마다 확인을 해주어야 하는 문제가 있었습니다.

이 과정에서 지속적으로 요청을 보내면 서버는 그 응답을 지속적으로 주어야 하기 때문에 서버에 부하가 생길 수 있습니다.

SSE를 사용하지않고 WebSocket을 통해 알림 기능을 구현하는 것도 고려했습니다.
하지만, WebSocket은 양방향 통신을 지원하는 프로토콜로, 채팅 기능처럼 실시간 상호작용이 필요한 경우에는 적합하지만, 알림 기능처럼 단방향으로 서버에서 클라이언트로만 데이터를 전송하는 용도에는 적합하지 않다고 판단했습니다.

모든 로그인한 사용자가 WebSocket을 통해 알림을 받기 위해 서버와 연결을 유지하는 것은 서버의 부담이 될 수 있기 때문입니다.

하지만 SSE는 웹 소켓처럼 별도의 프로토콜을 사용하는 것이 아닌 http 프로토콜에서 동작하는 단방향 통신이므로 서버에 훨씬 적은 부하를 줍니다.
또한 WebSokcet보다 훨씬 적은 비용으로 동작 가능다는 이유로 SSE를 선택하여 알림 기능을 구현 하였습니다.

화면처럼 SSE 맵을 등록하고 초대 이벤트, 댓글이벤트가 발생하면 알림이 전송하는 코드를 구현했습니다.

그리고 채팅창 초대알림이 정상정으로 가는것을 확인할 수 있습니다.

여기까지가 저희가 준비한 내용입니다. 이상으로 PHCCS 프로젝트 백엔드 구성 및 주요 기술에 대한 설명을 마치겠습니다. QnA 시간 갖고 발표를 마치도록 하겠습니다.

profile
Back-end Developer를 목표로 하고 있는 전진구입니다.

0개의 댓글