본문 바로가기

Spring

[Spring] @AuthenticationPrincipal null

문제상황

@PostMapping()
public ResponseEntity<? extends BaseResponseBody> createConference(@AuthenticationPrincipal SsafyUserDetails userDetails) {
    conferenceService.createConference(userDetails.getUser().getUserId());
    return ResponseEntity.status(201).body(BaseResponseBody.of(201, "Success"));
}

프로젝트를 진행할 때 SpringSecurity와 JWT Token 기술이 적용된 스켈레톤 코드를 받아서 진행하는데 늘 사용하던 @AuthenticationPrincipal 어노테이션을 사용하니 UserDetails 인터페이스를 구현한 클래스가 계속 null 값이 떴다. 

문제원인

사용자 요청이 들어오면 AuthenticationFilter가 요청을 가로챈 후 getAuthentication() 메서드로 UsernamePasswordAuthenticationToken 객체를 생성하는데 이때 토큰의 파라미터로 String 값인 userId를 넣어준 것이 원인이었다.

/**
 * 요청 헤더에 jwt 토큰이 있는 경우, 토큰 검증 및 인증 처리 로직 정의.
 */
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {
    ...

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        ...

        try {
            Authentication authentication = getAuthentication(request);
            // jwt 토큰으로 부터 획득한 인증 정보(authentication) 설정.
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } 

        ...
    }

    @Transactional(readOnly = true)
    public Authentication getAuthentication(HttpServletRequest request) throws Exception {
        ...
        
        // 식별된 정상 유저인 경우, 요청 context 내에서 참조 가능한 인증 정보(jwtAuthentication) 생성.
        SsafyUserDetails userDetails = new SsafyUserDetails(user);
        UsernamePasswordAuthenticationToken jwtAuthentication = new UsernamePasswordAuthenticationToken(userId,
                null, userDetails.getAuthorities());
                
        ...
    }
}

해결방법

아래와 같이 첫번째 파라미터인 userId를 UserDetails 인터페이스를 구현한 클래스로 바꿔주었더니 UserDetails 구현클래스가 잘 넘어온 것을 확인할 수 있었다.

@Transactional(readOnly = true)
public Authentication getAuthentication(HttpServletRequest request) throws Exception {
    ...

    // 식별된 정상 유저인 경우, 요청 context 내에서 참조 가능한 인증 정보(jwtAuthentication) 생성.
    SsafyUserDetails userDetails = new SsafyUserDetails(user);
    UsernamePasswordAuthenticationToken jwtAuthentication = new UsernamePasswordAuthenticationToken(userDetails,
            null, userDetails.getAuthorities());

    ...
}