SecurityContextHolder
를 사용하여 프론트에서 사용자 정보를 받지 않고도 사용자를 가져올 수 있다.
예를 들어, 게시판 사이트를 운영하는데 내가
(id=2)
쓴 글만 보고 싶어 서버에 데이터를 요청할 때/posts/list/2
와 같이userId
를 같이 보내야 한다면 타인이 접근할 수도 있다는 문제가 있다.하지만,
SecurityContextHolder
를 사용한다면 로그인한 사용자의 데이터를 서버 자체적으로 받아올 수 있다.
이전 글에서 토큰을 통한 데이터 요청을 다루었는데,
JwtAuthenticationFilter
에서SecurityContextHolder
에 유저 정보를 저장하였다.JwtAuthenticationFilter.class
@RequiredArgsConstructor public class JwtAuthenticationFilter extends GenericFilterBean { private final JwtTokenProvider jwtTokenProvider; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 헤더에서 토큰 받아오기 String token = jwtTokenProvider.resolveToken((HttpServletRequest) request); // 토큰이 유효하다면 if (token != null && jwtTokenProvider.validateToken(token)) { // 토큰으로부터 유저 정보를 받아 Authentication authentication = jwtTokenProvider.getAuthentication(token); // SecurityContext 에 객체 저장 SecurityContextHolder.getContext().setAuthentication(authentication); } chain.doFilter(request, response); } }
SecurityContextHolder
에 저장된 유저 정보를 사용하여 로그인한 유저를 구하는 함수를 작성해 보자.
우리 프로젝트에는
common
패키지 안에U
라는 클래스가 존재한다.
U.class
의 코드는 다음과 같다.public class U { // 현재 request 구하기 public static HttpServletRequest getRequest() { ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); return attrs.getRequest(); } // 현재 session 구하기 public static HttpSession getSession() { return getRequest().getSession(); } // 현재 로그인한 사용자 UserDetail 구하기 public static User getLoggedUser() { // 현재 로그인한 유저 정보 UserDetails userDetails = (UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal(); return (User) userDetails; } }
getLoggedUser
함수를 보면,SecurityContextHolder
의 유저정보를UserDetail
에 담고, 다시User
에 담아 반환한다.
이제 사용방법에 대해 알아보자.
예시로, 해당 달의 자신이 쓴 일기 리스트를 반환하는 함수를 보여 주겠다.
MemoService.class
public List<Memo> getMemoList(Integer year, Integer month) { Long userId = getUserId(); LocalDate firstDate = LocalDate.of(year, month, 1); LocalDate lastDate = firstDate.withDayOfMonth(firstDate.lengthOfMonth()); List<Memo> memoList = memoRepository.findByUserIdAndDateBetween(userId, firstDate, lastDate); return memoList; }
userId
를 함수 인자가 아닌,getUserId()
를 통해 받아오고 있다.
getUserId
함수는 다음과 같다.private Long getUserId() { Long userId = U.getLoggedUser().getId(); if (userId == null) throw new MyMemoryException(404, "잘못된 유저입니다."); userRepository.findById(userId).orElseThrow(() -> { return new MyMemoryException(404, "올바르지 않은 유저입니다."); }); return userId; }
첫 줄을 보면,
U.getLoggedUser
를 통해 유저를 받아오고 있다.
이러한 방식을 통해
- 토큰 복호화
- 서버의
SecurityContextHolder
에 유저정보 저장U.getLoggedUser
로 로그인 한 유저 정보 가져오기단계로 사용자 정보를 가져올 수 있게 된다.