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

2024. 10. 15. 21:16내일배움캠프/Schedule Management

 원래라면 JWT 를 프로젝트에 반영하면서 부터 구현했어야 하는 것이 맞지만 이후 요구사항 반영을 위해 미루어 왔던 'Access Token' 재발급에 대한 내용과 '관리자(ADMIN)' 권한을 가진 관리자 계정에 대한 부분을 해당 게시글에 기록하고자 한다. 이번에 프로젝트에 반영된 내용은 여기서 확인이 가능하다.

 

1. Access Token 재발급

 이전 게시물에서도 몇 번 언급했지만 과제에 주어진 요구사항에는 'Access Token' 에 대한 내용만 있을 뿐 'Refresh Token' 에 대한 내용은 없다. 하지만 이번 기회에 'Refresh Token' 또한 활용해보고 싶었기에 개인적으로 추가한 상태이다. Access Token 의 사용목적은 '인증/인가' 이며, Refresh Token 의 사용목적은 'Access Token 재발급' 이다.

 

Refresh Token 을 추가하게 되면서 내가 그린 'Access Token 재발급' 시나리오는 아래와 같다.

  1. 클라이언트는 헤더에 Access Token 을 담아 요청(인증이 필요한) → 서버에서 토큰 만료 확인
  2. 클라이언트는 응답 확인 ← 서버는 Access Token 만료 알림
  3. 클라이언트는 헤더에 Refresh Token 을 담아 재발급 요청 → 서버에서 토큰 확인
  4. 클라이언트는 응답 확인 ← 서버는 재발급한 Access Token 을 반환
  5. 클라이언트는 재발급된 Access Token 을 사용해 재요청 → 서버에서 토큰 인증

(3)의 경우 만약 Refresh Token 조차 만료되었거나 유효하지 않은 경우 클라이언트는 다시 로그인해야 된다. 물론 해당 부분은 백엔드 쪽에서 모두 정하기에는 무리가 있으므로 대부분 나의 '가정(시나리오)' 에 이루어지긴 했다.

 

Access Token 이 유효하지 않은 경우(만료, 유효성, 빈 토큰 등) 요청이 수행되지 않도록 작성했기 때문에 Access Token 재발급에 필요한 API 를 아래와 같이 추가 했다.

@RestController
@RequestMapping("/token")
public class RefreshTokenController {
    private final RefreshTokenService refreshTokenService;

    public RefreshTokenController(RefreshTokenService refreshTokenService) {
        this.refreshTokenService = refreshTokenService;
    }

    @PostMapping("/reissue")
    @ResponseStatus(HttpStatus.OK)
    public ResponseReissueToken reissueAccessToken(@RequestHeader(name = "Authorization") String refreshToken,
                                                   @RequestAttribute(name = "member") Member member) {
        return refreshTokenService.reissue(refreshToken, member);
    }
}

 

필터에서 Refresh Token 으로 인증을 진행한 후 통과되면 Controller 에서 Refresh Token 과 회원 정보를 HttpServletRequest 에서 꺼내 'Service' 의 'reissue()' 메서드를 호출한다.

 

'reissue()' 메서드는 전달받은 Refresh Token 이 REFRESH_TOKEN 테이블에 존재하는지 확인존재한다면 Access Token 을 새로 생성한다. 이때 토큰 생성에 필요한 정보는 전달받은 회원 정보(member)를 사용한다. 이후 응답 DTO 에 새로 생성한 Access Token 을 담아 반환한다.

Access Token 재발급 요청

 

API 테스트를 통해 새로운 Access Token 이 반환된 것을 확인 할 수 있었다. 물론 요청 헤더에 유효한 Access Token 을 담아도 새로운 Access Token 이 발급된다. 하지만 위의 시나리오를 따른다면 헤더에 Access Token 이 들어올 일은 없다.

 

 

2. 관리자(ADMIN) 계정 생성

 풀어 설명하면 관리자(ADMIN) 권한을 갖는 회원을 어떻게 다룰 것인지에 대한 고민이 있었다. 이전에 '네이버 카페' 를 클론 코딩할 때는 카페 생성자를 관리자로 생성했지만 이번 과제 요구사항만으로는 그러한 흐름을 반영하기 어려웠다. 그래서 관리자 계정(= 관리자 회원)은 직접 DB 에 쿼리로 추가하는 방식을 사용했다.

INSERT INTO member (name, email, password, role, create_at, update_at)
VALUES ('관리자', 'root@gmail.com', '$2a$04$tbGequEs0rH.Q.ERNIyjJexuWTdQ.22sUYrd4Uhb1nYy9RSVGM5dG', 'ADMIN', now(), now());

 

MySQL Command line Client 를 사용해 직접 MEMBER 테이블에 관리자 계정 정보를 추가한 것이다. 이러한 방법을 사용한 것은 '관리자' 를 다루는 내용의 요구사항이 주어지지 않아 구현하는 방식이 너무 다양해졌기 때문이다. 또한 구현을 하자니 요구사항에 벗어나는 내용이 많았던 것도 있다. 그래서 위 처럼 직접 DB 에 데이터를 추가하는 방식을 택했다.

 

해당 방식을 택하면서 고려했던 것은 계정의 '비밀번호' 이다. 애초에 비밀번호 원본을 암호화해 DB 에 저장하고 있으므로 관리자 계정을 추가할 때 비밀번호가 같은 방식으로 암호화되어 있을 필요가 있었다. 그래서 다른 임시 프로젝트에 현 프로젝트와 같은 방식으로 원본을 암호화하고 그 값을 그대로 가져다가 관리자 계정 추가시 '비밀번호' 값으로 사용했다.

 

내심 "혹시 복호화(Decode) 가 안되면 어떡하지?" 라는 걱정과는 다르게 관리자 계정으로 잘 로그인 되는 것을 확인할 수 있었다.

관리자 계정 로그인