2023-01-11
우선 지난번에 만들었던 코드를 그 때 당시에는 완전히 정리를 하지는 못 하고 끝낸 상태였다...
뭐 애초에... 이 아래에 있는 코드가 즉, 지난번에 적은 코드는 정리를 해서 올린거기는 했다...
다만, 지나번 글에서 정리하기에는 이미 너무 뇌가 과부화 상태여.. 는 사실 핑계....
그냥 오늘 이 부분을 다시 한번 더 정리를 하고, 웹소켓 부분이 추가됨으로 인해 그 부분에 대한 설명이 필요했 ㄷ...
// 헤더값 추출 및 회원 검증
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 으로 가져와서 처리해주기로 했다.
방법은...
- @ 가 들어있으면 회원은 반드시 이메일 정보를 양식에 맞게 입력해야 하기 때문에, @ 를 받아오면 회원으로 판단하고 시작한다.
- 문자열 형태로 받아왔을 때 식별자인 "Bearer " 부터 시작하면 웹소켓으로 부터 받아온 것으로 확인하고 시작한다.
- 그 외의 경우에는 비회원으로 확인하고 시작한다.
위의 과정을 거치면서 인증 및 회원이 가지고있는 필수 정보를 받아서 사용할 수 있는 부분을 하나의 모듈만을 사용해서 사용가능하게 만들었다.
위 이미지 처럼 validHeader 와 gamerInfo 이 2개의 메서드만 사용하면 회원, 비회원 정보를 받아와서 처리가 가능해진다 !!!
또, 아래 이미지처럼 세션에서 쓰이는 토큰은 매개변수가 문자열이기 때문에 gamerInfo 메서드만 사용해도 회원정보를 받아올 수 있게 되었다.
어찌보면... 당연히 해줘야 하는 기능일지 모르지만...
이번처럼 본격적으로 혼자서 생각해서 모듈화해서 사용해보니 나도, 팀원들도 굉장히 편하게 전역에서 회원정보를 인증까지 거쳐서 쉽게 빼내올 수 있었다.
물론... 내가 짠 코드이기 때문에 이를 쓰기 위해서 이해를 하고 쓰는것이 좋기 때문에 이를 다른팀원 분들이 이해하기 쉽게 주석도 꼼꼼하게 달고 설명도 해 줘야 했지만, 이것도 재밌는 경험이었다.
그리고 무엇보다...
이게 잘 작동했을 때...
다른 사람들이 쓰면서 편하다고 해줬을 때...
너무 기분이 좋았다 !!!!!
생각보다 모듈화 하는게 힘들어서 좀 오래걸린 작업이었지만, 그래도 재밌는 경험이었던 것 같다.