Search

JWT 와 ContextHolder 를 잘 이용하려면?

태그
Security
JWT
목차

JWT 토큰 에는 무엇을 넣었나요?

일단은 userId 만 넣었습니다. 아직은 토큰과 친하지 않고 이 토큰이 얼마나 안전성이 있는지 깨닿지 못했기 때문입니다. 유저를 인증하는 과정에서 꺼내쓰기에 좋은 값만 넣은 셈이죠.

이전에 작성한 코드를 보아하니

예전에 프로젝트를 하며 작성한 코드를 보니 이상하게 유저정보를 조회 하더군요..
public Member getCurrentMember(HttpServletRequest request) { String accessToken = tokenUtil.getJWTTokenFromHeader(request); String userId = tokenUtil.getUserIdFromToken(accessToken); return memberRepository.findById(Long.valueOf(userId)) .orElseThrow(() -> new ApiException(ErrorType.USER_NOT_FOUND)); }
Java
복사
헤더에서 토큰을 추출하고, 여기에서 유저 아이디를 추출한 뒤 이를 토대로 유저를 찾아 반환 했습니다.

왜 그랬을까?

UsernamePasswordAuthenticationToken.java

UsernamePasswordAuthenticationToken 생성시 Userdetails 에 userEmail 만 넣었기 때문에 principal 을 사용하더라도 컨텍스트홀더에서 유저 이메일밖에 꺼낼게 없었습니다.
 principal 이 뭔지 모르겠다면? 아래 글을 확인해보세요!
결론적으로는 컨텍스트 홀더를 이용하더라도 이메일을 통해 멤버 객체를 찾아야 했던 셈!
@Override public Authentication authenticate(Authentication authentication) { final UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication; // AuthenticationFilter 에서 생성된 토큰으로 부터 아이디와 비밀번호 조회 final String email = token.getName(); final String password = (String) token.getCredentials(); // UserDetailsService 를 통해 DB 에서 아이디로 사용자 조회 final CustomUserDetails userDetails; try { userDetails = (CustomUserDetails) userDetailsService.loadUserByUsername(email); } catch (Exception e) { throw new RuntimeException(e); } if (!bCryptPasswordEncoder.matches(password, userDetails.getPassword())) { throw new BadCredentialsException("비밀번호가 일치하지 않습니다."); } return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities()); }
Java
복사

JWT

토큰 생성시 Subject 로 유저 아이디를 넣었기 때문에, 멤버객체를 사용하려면 id 로 조회 해서 찾아야 했습니다. 이러나 저러나 유저를 찾아와야 하는 셈 이였죠.

그래서 결론은?

User 객체를 사용해야 하는경우

User 엔티티와 매핑되어있는 다른 엔티티의 값을 가져와야 하는 경우가 있을 겁니다. 이 경우에는 컨텍스트 홀더에 저장한 유저를 가져와 작업을 하면 됩니다. 불필요하게 유저정보를 또 조회할 필요가 없습니다. 아래와 같이 사용하면 편리하겠죠.
public Long getLoginUserIndex() { Optional<User> user = getLoginUser(); Long userId = user.get().getId(); return userId; } public Optional<User> getLoginUser() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Object principal = authentication.getPrincipal(); return (Optional<User>) principal; }
Java
복사

UserId 만 사용하거나, UserId 도 사용해야 하는 경우

하지만 단순히 userId 만 필요한 경우도 있습니다. 또한 현재 로그인한 유저와 요청자가 같은지 확인해야할 상황이 있을수도 있죠. 이때는 리퀘스트 헤더 안에 있는 토큰을 꺼내와 userId 를 추출합니다.