[일정 관리 앱] 리팩토링(2)

2024. 10. 15. 18:46내일배움캠프/Schedule Management

 이번에는 '유저(멤버)' 엔티티를 다루는 요청에 대한 모든 부분을 하나씩 확인하며 수정해 보려한다. 수정은 요청시 '인증 필요' 의 유무로 구분지어 나누어 진행했다. 이번 리팩토링을 통해 수정된 코드는 여기서 확인 가능하다.

  • 인증 불필요 : 회원 가입, 로그인
  • 인증 필요 : 그 외 모든 기능

과제의 요구사항에 따라 위와 같이 구분짓게 되었다.

 

1. 인증이 불필요한 요청

 아래의 요청들은 필터에서 인증/인가를 수행하지 않고 곧장 'MemberController' 에 'ServletRequest, ServletResponse' 를 전달하게 된다.

AuthFilter.doFilter() 메서드의 수행부 일부

 

1-1. 회원 가입

 '회원 가입' 에는 회원(유저)의 '이름, 이메일(계정 ID), 비밀번호(계정 비밀번호)' 정보를 전달 받아야 한다. 전달받은 정보로 새로운 회원에 대한 엔티티를 생성후 DB 에 저장하며, 신규 토큰(accessToken, refreshToken)들을 생성한다. 모든 과정을 마치면 신규 회원의 정보(비밀번호 제외)생성한 토큰들함께 반환해준다.

 

요구사항에서 회원가입시 JWT 를 생성해 반환해 주어야 한다고 명시되어있다. 이를 튜터님과 이야기를 통해 '회원가입 후 자동으로 로그인' 이라 가정하게 되었고 그 때문에 회원가입시 신규 회원 정보 또한 반환하게 되었다.

회원 가입 요청

 

가입 정보를 요청 정보로 전달받게 되면 아래의 과정으로 'MemberService' 의 'join()' 메서드가 수행된다.

  1. 가입정보(=요청정보)의 'email' 의 중복여부 확인 - with MEMBER 테이블의 'email' 컬럼
  2. Member 엔티티 생성 → 영속화
  3. JWT 생성 - accessToken, refreshToken
  4. RefreshToken 엔티티 생성 → 영속화
  5. 응답 DTO 생성후 반환

(1) 의 경우에 요청 정보의 'email' 을 사용하는 다른 회원이 있다면 아래와 같이 예외 코드와 메시지를 반환한다.

회원 가입 요청 - 이메일 중복

 

요청 수행 후 DB 의 member, refreshToken 테이블을 확인하면

회원 가입 후 - member 테이블(위), refresh_token 테이블(아래)

 

member 테이블에는 요청 정보가 잘 저장되었으며 요구사항에 명시한 대로 'password' 는 암호화된 상태로 DB 에 저장되어있다. refresh_token 테이블에는 방금 생성된 JWT 중 하나인 refreshToken 이 저장되어 있다. 해당 토큰 정보는 회원이 '로그아웃' 하게 되면 삭제 될 것이다.

 

1-2. 로그인

 '로그인' 에는 '이메일, 비밀번호' 정보를 전달해야 한다. 전달 받은 이메일을 가진 회원 정보를 찾아 요청 정보의 비밀번호와 조회한 회원의 비밀번호를 비교해 로그인 여부를 결정한다.

로그인 요청

 

로그인 정보를 전달받게 되면 아래와 같은 과정으로 'MemberService' 의 'logIn()' 메서드가 수행된다.

  1. 요청 정보의 'email '과 같은 데이터를 가진 회원 정보를 DB 에서 조회
  2. 요청 정보의 'password' 와 조회한 회원의 'password' 를 비교
  3. JWT 생성 - accessToken, refreshToken
  4. RefreshToken 엔티티 생성 → 영속화
  5. 응답 DTO 생성후 반환

(1) 의 과정에서 일치하는 회원 정보를 DB 에서 조회할 수 없을 경우 아래와 같이 예외 코드 및 메시지를 반환한다.

로그인 요청 - 잘못된 이메일

 

(2) 의 과정에서 회원의 비밀번호가 유효하지 않다면 아래와 같이 예외 코드 및 메시지를 반환한다.

로그인 요청 - 잘못된 비밀번호

 

로그인을 통해 생성되어 DB 에 저장된 'refreshToken' 또한 회원이 로그아웃하면 DB 에서 삭제될 것이다.

 

 

2. 인증이 필요한 요청

 로그아웃 및 회원(목록) 조회, 회원 정보 수정, 회원 삭제에 대한 요청은 인증이 필요하다. 인증/인가를 반영하기 전에는 쿼리 파라미터로 회원 엔티티의 ID 를 전달 받았지만 이제는 필터에서 조회한 회원 엔티티를 ServletRequest(HttpServletRequest) 에서 꺼내 해당 정보를 통해 요청을 수행하기만 하면 된다.

 

2-1. 로그아웃

 로그아웃에는 요청 헤더에 refreshToken 을 'Authorization' 키 값으로 담아서 요청을 해야한다.

로그아웃 요청

 

필터에서 refreshToken 을 통해 인증을 수행후 아래와 같은 과정으로 'MemberService' 의 'logOut()' 메서드를 수행한다.

  1. 요청 헤더의 refreshToken 과 같은 리프레시 토큰 엔티티를 'refresh_token' 테이블에서 조회한다.
  2. 'refresh_token' 테이블에서 조회한 리프레시 토큰 엔티티를 테이블에서 삭제한다.

(1) 의 과정이 적절한지는 좀 더 고민해 볼 필요가 있다. 일단 추가하게 된 이유는 'deleteByRefreshToken()' 메서드의 경우 반환값이 없어 제대로 삭제가 이루어졌는지 확인이 어렵다. 또한 쿼리를 확인해보면 조건에 해당하는 레코드를 삭제하는 쿼리이다. 그렇기에 조건에 해당하는 레코드가 없다면 그냥 아무일도 일어나지 않는다. 그래서 의미없는 쿼리를 막기 위해  'refresh_token' 테이블에 리프레시 토큰 엔티티를 조회해야 명확하게 클라이언트에 "로그아웃 처리가 완료 되었습니다." 라는 응답을 할 수 있을 것 같아 (1) 의 과정을 추가하게 되었다.

 

2-2. 회원 조회 및 회원 목록 조회

 조회의 경우 크게 바뀐 것이 없다 그저 인증/인가를 위해 요청 헤더에 'accessToken' 을 담아 요청하기만 하면된다. 요청 URL 이나 비즈니스 로직이 수정된 것은 없다.

 

2-3. 회원 정보 수정

 기존에는 수정할 회원을 식별하기 위해 쿼리 파라미터로 회원의 ID 를 전달 받았다. 하지만 필터를 통해 인증을 수행하며 토큰을 발급받은 회원을 DB 에서 조회해 ServletRequest 에 담아 전달받기에 더이상 쿼리 파라미터로 정보를 수정할 회원을 식별할 필요도 없어졌다. 또한 이미 DB 에서 조회한 회원이기에 Service 계층에서 수정 대상 회원의 정보를 조회할 필요도 없어졌다.

 

그저 ServletRequest 에 담긴 회원 정보를 수정하고 커밋해 DB 에 반영하기만 하면 된다.

회원 정보 수정

 

요청 헤더에 'accessToken', 요청 Body 에 수정 정보를 담아 요청하기만 하면된다. DB 를 통해 수정한 정보가 잘 반영되는 것 또한 확인했다.

 

2-4. 회원 삭제(탈퇴)

 삭제의 경우도 '회원 정보' 수정과 같다. 요청 헤더에 DB 에서 조회한, 삭제 대상인 회원 정보가 담겨있어 요청 헤더의 회원 정보를 DB 에서 삭제해 주기만 하면 된다.

회원 삭제 요청

 

DB 를 통해 요청한 회원의 정보가 잘 삭제되는 것 또한 확인했다.