일기

2023-01-11

SHsus 2023. 1. 11. 22:58

우선 지난번에 만들었던 코드를 그 때 당시에는 완전히 정리를 하지는 못 하고 끝낸 상태였다...

 

뭐 애초에... 이 아래에 있는 코드가 즉, 지난번에 적은 코드는 정리를 해서 올린거기는 했다...

 

다만, 지나번 글에서 정리하기에는 이미 너무 뇌가 과부화 상태여.. 는 사실 핑계....

 

그냥 오늘 이 부분을 다시 한번 더 정리를 하고, 웹소켓 부분이 추가됨으로 인해 그 부분에 대한 설명이 필요했 ㄷ...

 

// 헤더값 추출 및 회원 검증
public String validHeader(HttpServletRequest request) {
    String userToken = request.getHeader("Authorization");                 // 유저 헤더값 추출
    String guestInfo = request.getHeader("guest");                         // 게스트 헤더값 추출
    if (userToken != null) {
        Claims claims = jwtUtil.authorizeToken(request);                        // 유저 검증
        return claims.get("email").toString();                                  // 이메일 값만을 반환
    } else {
        return guestInfo;
    }
}

// 회원 Id, Nickname 추출
public HashMap<String, String> gamerInfo(String token) {
    HashMap<String, String> result = new HashMap<>();                           // 결과물을 담기위한 HashMap
    // 1. 회원, 비회원 분기처리 시작
    if (token.contains("@")) {
        // 2. 문자열 안에 @ 가 있으면 request 로 받아온다. 유저가 사용한다고 판단하고 시작
        // request 를 통해 받아온 값은 email 이기 때문에 @ 을 포함하고 있다.
        // 그래서 validHeader 를 통한 결과값이 회원 이메일을 받아온 것이므로 회원 기준으로 시작
        User user = userRepository.findByEmail(token).orElseThrow(
                () -> new CustomException(StatusMsgCode.USER_NOT_FOUND)
        );
        result.put(GamerEnum.ID.key(), user.getId().toString());                // 회원 Id 를 key 값으로 value 추출 해서 result 에 주입
        result.put(GamerEnum.NICK.key(), user.getNickname());                   // 회원 닉네임을 key 값으로 value 추출 해서 result 에 주입
        result.put(GamerEnum.IMG.key(), user.getImgUrl());                      // 회원 img url 을 key 값으로 value 추출 해서 result 에 주입
    } else if (token.startsWith("Bearer ")) {
        // 3. 문자열의 시작이 Bearer 이면 문자열 형태로 받아오는 webSession 에서 사용된다고 판단하고 시작
        Claims claims = jwtUtil.authorizeSocketToken(token);                    // 검증 및 정보 가져오기
        String email = (String) claims.get("email");                            // 토큰에서 이메일 값만을 추출
        User user = userRepository.findByEmail(email).orElseThrow(
                () -> new CustomException(StatusMsgCode.USER_NOT_FOUND)
        );
        result.put(GamerEnum.ID.key(), user.getId().toString());                // 회원 id 를 key 값으로 value 추출 해서 result 에 주입
        result.put(GamerEnum.NICK.key(), user.getNickname());                   // 회원 닉네임을 key 값으로 value 추출 해서 result 에 주입
        result.put(GamerEnum.IMG.key(), user.getImgUrl());                      // 회원 img url 을 key 값으로 value 추출 해서 result 에 주입
    } else {
        // 4. 위의 분기에 해당하지 않을 경우에는 guest 라고 판단하고 시작
        token = URLDecoder.decode(token, StandardCharsets.UTF_8);               // 비회원의 토큰 정보를 얻기 위해서 디코딩
        // 게스트의 원하는 정보를 뽑아서 사용하기 위해서 배열에다가 하나씩 넣어준다.
        // guestInfo 예시 형태 : "10001,유저닉네임"
        String[] guestInfo = token.split(",");
        // 게스트 유정 Redis DB 에 존재하는지 확인(검증)
        Optional<Guest> guest = Optional.ofNullable(guestRepository.findById("guest:" + guestInfo[0]).orElseThrow(
                () -> new CustomException(StatusMsgCode.INVALID_AUTH_TOKEN)));
        result.put(GamerEnum.ID.key(), guestInfo[0]);                           // guest Id 를 key 값으로 value 추출 해서 result 에 주입
        result.put(GamerEnum.NICK.key(), guestInfo[1]);                         // guest 닉네임을 key 값으로 value 추출 해서 result 에 주입
        result.put(GamerEnum.IMG.key(), guestInfo[2]);                          // guest img url 을 key 값으로 value 추출 해서 result 에 주입
    }
    return result;
}

 

위 처럼 코드를 모듈화 시켜서 해당 메서드를 다른 클래스에서 사용할 때 호출만 해주면 검증과정을 거쳐서 HashMap 형태로 결과물을 받을 수 있다.

 

그래서 이를 받아서 까보면 정보가 어디서부터 넘어왔는지 알 수 있다.

원래는 회원, 비회원에 관련한 정보들만을 받아올 수 있었는데 팀원분께서 만드신 웹소켓 만들어주신 코드가 HttpServletRequest 형태가 아닌 String 형태로 받아온다.

그래서 HashMap 형태로 받아서 출력하는 메서드가 작동하기 이전에 헤더에서 값을 빼내는 로직이 HttpServletRequest 으로 받아오는데 이 부분이 웹소켓에서 토큰을 String 으로 건네주기 때문에 앞의 코드를 받을수가 없다.

 

따라서, 웹세션 ID 를 받을 때 토큰을 String 으로 가져와서 처리해주기로 했다.

방법은...

 

  1. @ 가 들어있으면 회원은 반드시 이메일 정보를 양식에 맞게 입력해야 하기 때문에, @ 를 받아오면 회원으로 판단하고 시작한다.
  2. 문자열 형태로 받아왔을 때 식별자인 "Bearer " 부터 시작하면 웹소켓으로 부터 받아온 것으로 확인하고 시작한다.
  3. 그 외의 경우에는 비회원으로 확인하고 시작한다.

위의 과정을 거치면서 인증 및 회원이 가지고있는 필수 정보를 받아서 사용할 수 있는 부분을 하나의 모듈만을 사용해서 사용가능하게 만들었다.

 

 

일반적으로 회원 정보를 이용하는 부분
회원에 세션 ID 를 넣어주기 위한 부분

 

위 이미지 처럼 validHeader 와 gamerInfo 이 2개의 메서드만 사용하면 회원, 비회원 정보를 받아와서 처리가 가능해진다 !!!

또, 아래 이미지처럼 세션에서 쓰이는 토큰은 매개변수가 문자열이기 때문에 gamerInfo 메서드만 사용해도 회원정보를 받아올 수 있게 되었다.

 

어찌보면... 당연히 해줘야 하는 기능일지 모르지만...

이번처럼 본격적으로 혼자서 생각해서 모듈화해서 사용해보니 나도, 팀원들도 굉장히 편하게 전역에서 회원정보를 인증까지 거쳐서 쉽게 빼내올 수 있었다.

물론... 내가 짠 코드이기 때문에 이를 쓰기 위해서 이해를 하고 쓰는것이 좋기 때문에 이를 다른팀원 분들이 이해하기 쉽게 주석도 꼼꼼하게 달고 설명도 해 줘야 했지만, 이것도 재밌는 경험이었다.

 

그리고 무엇보다...

이게 잘 작동했을 때...

다른 사람들이 쓰면서 편하다고 해줬을 때...

 

너무 기분이 좋았다 !!!!!

 

생각보다 모듈화 하는게 힘들어서 좀 오래걸린 작업이었지만, 그래도 재밌는 경험이었던 것 같다.