인터셉터가 개발자가 사용하기 더 편하고 제공하는 기능이 더 많으며 인터셉터를 사용하면 Spring AOP 를 사용해서 JWT 인증을 어노테이션으로 관심사 분리를 할 수 있기 때문에 인터셉터를 활용하여 JWT 인증을 하는게 좋다고 생각할 수 있다. 하지만 여기에는 함정이 있다.

먼저 FilterInteceptor 의 차이점에 대해 알아보자.

Filter와 Interceptor의 차이점

Filter

  • 서블릿 사양의 일부로, 서블릿 컨테이너에서 실행된다.

  • 모든 요청에 대해 동작하며, Spring Context 외부의 요청과 응답도 처리할 수 있다. 이는 Spring SecuritySpring MVC 밖에서도 작동할 수 있게 하는 핵심적인 이유이다.

  • Spring Security 는 자체 필터 체인을 통해 인증과 인가 과정을 관리하며, 사용자 정의 필터를 이 체인에 쉽게 추가할 수 있다.

  • 필터는 요청이 DispatcherServlet 에 도달하기 전에 실행된다. 따라서 인증과 같이 모든 요청에 대해 처리해야 하는 로직을 구현하기에 적합하다.

Interceptor

  • Spring MVC 의 일부로, DispatcherServlet 이 컨트롤러를 호출하기 전, 후 그리고 완료 후에 추가 작업을 수행할 수 있도록 한다.

  • Spring Context 내부에서만 작동하며, 주로 컨트롤러의 실행을 가로채는 데 사용된다.

  • 인증보다는 요청의 사전 처리, 로깅, 트랜잭션 관리 등에 더 적합하다.

  • 사용자 정의 인터셉터를 구성하기 쉽고, 요청과 응답에 대한 높은 수준의 제어를 제공한다.

FilterInterceptor 그리고 DispatcherServlet 에 대해 더 알고 싶다면 이 링크의 글을 읽어보자

왜 Filter에서 JWT 인증을 처리하는가?

  1. Spring Security 의 아키텍처 : Spring Security 는 광범위한 보안 요구 사항을 처리하기 위해 설계된 복잡한 필터 체인을 가지고 있다. 이 체인은 인증과 인가 과정을 관리하며, JWT 인증 로직을 필터로 구현하면 이 체인에 자연스럽게 통합된다.

  2. 요청 처리의 초기 단계에서 인증 : 인증은 보통 요청 처리의 가장 초기 단계에서 이루어져야 한다. 필터는 Spring MVCDispatcherServlet 에 요청이 도달하기 전에 실행되므로, 모든 요청에 대해 인증 로직을 수행하기에 적합하다.

  3. 보안 컨텍스트 설정 : 인증 후, 사용자의 보안 컨텍스트를 설정해야 하는데, 이는 Spring Security 의 필터 체인을 통해 자연스럽게 처리된다. 인증 정보는 Spring SecuritySecurityContextHolder 에 저장되며, 이 정보는 요청 처리 과정에서 다른 필터와 Spring MVC 컨트롤러에서 접근할 수 있다.

  4. 편의성 및 통합성 : Spring Security 는 JWT 인증을 포함한 다양한 보안 매커니즘을 필터를 통해 제공하고 있으며, 이를 사용하면 별도의 인증 처리 로직을 구현할 필요 없이 효율적으로 보안 요구사항을 충족할 수 있다.

Interceptor 는 매우 유용하고 강력한 도구이지만, 인증과 같은 보안 관련 로직을 처리하기에는 몇 가지 제약 있다.

Interceptor의 제약 사항

  1. Spring MVC 에 한정된 실행 : InterceptorSpring MVC 의 컨텍스트 내에서만 실행되므로, Spring MVC 를 통하지 않는 요청(예: 정적 리소스 접근, 다른 종류의 서블릿 요청 등)은 처리할 수없다. 반면, 필터는 서블릿 컨테이너 수준에서 작동하므로 모든 요청에 대한 인증 로직을 적용할 수 있다.

  2. 보안 처리에 필요한 초기 단계 실행의 어려움 : 보안 처리는 요청 처리의 매우 초기 단계에서 이루어져야 한다. InterceptorDispatcherServlet 에 의해 관리되므로, 요청이 Spring MVC 에 도달하기 전에 이미 필요한 보안 처리가 완료되어야 하는 경우가 많다. 필터는 이러한 요구 사항을 자연스럽게 충족시킬 수 있다.

  3. Spring Security 와의 통합 : Spring Security 는 보안 관련 처리를 위한 복잡한 필터 체인을 제공한다. 이 체인 내에서 인증 및 인가 과정을 관리하며, 사용자 정의 필터를 쉽게 추가할 수 있다. Interceptor 를 사용하는 경우, Spring Security 의 기존 구조와 별도로 동작하기 때문에, 보안 처리를 위한 일관된 방식을 유지하기 어렵다.

Spring Security와 JWT를 활용한 인증 구현

1. 의존성 추가

관련된 의존성을 추가한다.

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'io.jsonwebtoken:jjwt:0.9.1'
}

2. JWT(JSON Web Token) 처리를 위한 기본 속성들 저장

  • application.properties

설정 파일을 통해 설정 값들을 중앙 집중화하여 관리할 수 있으며, 프로파일에 따라 다른 설정을 적용할 수 있다.

# JWT
jwt.secret=Popcorn
jwt.expiration=86400000

3. Filter 구현

  • OncePerRequestFilter 를 상속 받아서 구현한다.

OncePerRequestFilter 를 상속 받는 이유

OncePerRequestFilterSpring Security의 필터 중 하나로, 하나의 요청에 대해 한 번만 실행되도록 보장하는 필터이다. 이는 서블릿 컨테이너에 의해 요청이 여러 번 처리될 수 있는 상황(요청이 여러번 처리 되는 이유)에서 특히 유용하다. 예를 들어, 요청이 디스패치되어 여러 필터를 거치는 경우(예: 에러 페이지로의 리디렉션, 요청의 내부 포워딩 등) 하나의 요청에 대해 해당 필터가 여러 번 실행되는 것을 방지한다.

@Slf4j
@Component
@Profile({"local", "server"})
@RequiredArgsConstructor
public class JwtRequestFilter extends OncePerRequestFilter {

    public static final String TOKEN_PREFIX = "Bearer ";
    public static final String HEADER_STRING = "Authorization";
    private static final List<String> EXCLUDE_URL = List.of(
            "/api/user/external/oauth/token",
            "/favicon.ico",
            "/swagger/**",
            "/swagger-resources/**",
            "/swagger-ui/**", "/webjars/**", "/swagger-ui.html",
            "/v3/api-docs/**"
    );
    @Value("${jwt.secret}")
    public static String SECRET;
    @Value("${jwt.expiration-time}")
    public static int EXPIRATION_TIME;

    @Override
    protected void doFilterInternal(HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException {
        try {
            final String jwtHeader = request.getHeader(HEADER_STRING);
            log.info("JWT Filter 진입");
            if (pathMatchesExcludePattern(request.getRequestURI())) {
                filterChain.doFilter(request, response);
                return;
            }

            if (jwtHeader == null || jwtHeader.isEmpty()) {
                request.setAttribute("exception", JwtErrorCode.NOTFOUND_TOKEN);
                throw new JwtFilterException(JwtErrorCode.NOTFOUND_TOKEN);
            }

            if (!jwtHeader.startsWith(TOKEN_PREFIX)) {
                request.setAttribute("exception", JwtErrorCode.UNSUPPORTED_TOKEN);
                throw new JwtFilterException(JwtErrorCode.UNSUPPORTED_TOKEN);
            }

            String token = jwtHeader.replace(TOKEN_PREFIX, "");
            request.setAttribute("userCode", JWT.require(Algorithm.HMAC512(SECRET)).build().verify(token).getClaim("id").asLong());
        } catch (TokenExpiredException e) {
            request.setAttribute("exception", JwtErrorCode.EXPIRED_TOKEN);
            throw new JwtFilterException(JwtErrorCode.EXPIRED_TOKEN);
        } catch (JWTVerificationException e) {
            request.setAttribute("exception", JwtErrorCode.WRONG_TYPE_TOKEN);
            throw new JwtFilterException(JwtErrorCode.WRONG_TYPE_TOKEN);
        } catch (JwtFilterException e) {
            filterChain.doFilter(request, response);
            return;
        }
        filterChain.doFilter(request, response);
    }

    private boolean pathMatchesExcludePattern(String requestURI) {
        AntPathMatcher pathMatcher = new AntPathMatcher();
        for (String excludeUrl : EXCLUDE_URL) {
            if (pathMatcher.match(excludeUrl, requestURI)) {
                return true;
            }
        }
        return false;
    }
}

jwt 속성 정의

public static final String TOKEN_PREFIX = "Bearer ";
public static final String HEADER_STRING = "Authorization";
private static final List<String> EXCLUDE_URL = List.of(
		"/api/user/external/oauth/token",
        "/favicon.ico",
        "/swagger/**",
        "/swagger-resources/**",
        "/swagger-ui/**", "/webjars/**", "/swagger-ui.html",
        "/v3/api-docs/**"
);
@Value("${jwt.secret}")
public static String SECRET;
@Value("${jwt.expiration-time}")
public static int EXPIRATION_TIME;

application.properties 에 정의한 속성을 불러오고, 앞으로 사용할 상수들과 인증을 제외할 URL List 들을 정의한다.

doFilter 구현

doFilterinternal 을 오버라이딩해서 필터의 로직을 구현하면 된다.

주석의 설명을 보자.

예외 처리에 대한 설명은 밑에 다시 설명하겠다. 이번에는 그냥 예외를 request 에 담아서 보내는구나 정도로 이해하자.

@Override
protected void doFilterInternal(HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException {
    try {
        final String jwtHeader = request.getHeader(HEADER_STRING);
        log.info("JWT Filter 진입");
        if (pathMatchesExcludePattern(request.getRequestURI())) {
            filterChain.doFilter(request, response);
            return;
        }

        if (jwtHeader == null || jwtHeader.isEmpty()) {
            request.setAttribute("exception", JwtErrorCode.NOTFOUND_TOKEN);
            throw new JwtFilterException(JwtErrorCode.NOTFOUND_TOKEN);
        }

        if (!jwtHeader.startsWith(TOKEN_PREFIX)) {
            request.setAttribute("exception", JwtErrorCode.UNSUPPORTED_TOKEN);
            throw new JwtFilterException(JwtErrorCode.UNSUPPORTED_TOKEN);
        }

        String token = jwtHeader.replace(TOKEN_PREFIX, "");
        request.setAttribute("userCode", JWT.require(Algorithm.HMAC512(SECRET)).build().verify(token).getClaim("id").asLong());
    } catch (TokenExpiredException e) {
        request.setAttribute("exception", JwtErrorCode.EXPIRED_TOKEN);
        throw new JwtFilterException(JwtErrorCode.EXPIRED_TOKEN);
    } catch (JWTVerificationException e) {
        request.setAttribute("exception", JwtErrorCode.WRONG_TYPE_TOKEN);
        throw new JwtFilterException(JwtErrorCode.WRONG_TYPE_TOKEN);
    } catch (JwtFilterException e) {
        filterChain.doFilter(request, response);
        return;
    }
    filterChain.doFilter(request, response);
}

// 인증 제외 URI 인지 확인하는 로직
private boolean pathMatchesExcludePattern(String requestURI) {
    AntPathMatcher pathMatcher = new AntPathMatcher();
    for (String excludeUrl : EXCLUDE_URL) {
        if (pathMatcher.match(excludeUrl, requestURI)) {
            return true;
        }
    }
    return false;
}

4. Filter 추가 - Spring Security 설정

이제 구현한 JWT 필터를 서블릿 컨테이너에게 사용하라고 알려주는 설정 작업을 해야 한다. Spring Security 에게 JwtRequestFilter를 사용하라고 알려주자.

원래는 SecurityConfig.java에서 WebSecurityConfigurerAdapter 을 상속받아 인가 기능을 구현하였다. 하지만 Spring Security 6.0 버전 기준으로 WebSecurityConfigurerAdapterdeprecated 되면서 더는 사용할 수 없다. SecurityFilterChainBean 으로 등록하여 사용하자.

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    public static final String FRONT_URL = "http://localhost:3000";
    private final CorsFilter corsFilter;
    private final JwtRequestFilter jwtRequestFilter;

    @Bean
    public BCryptPasswordEncoder encodePwd() {
        return new BCryptPasswordEncoder();
    }

    /**
     * SecurityFilterChain
     * <p>
     * WebSecurityConfigurerAdapter 가 deprecated 되면서 SecurityFilterChain 을 Bean 으로 등록하여 사용
     * </p>
     *
     * @param http HttpSecurity
     * @return SecurityFilterChain
     * @throws Exception 예외
     */
    @Bean
    @Order(SecurityProperties.BASIC_AUTH_ORDER)
    protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // http 시큐리티 빌더
        return http
                .httpBasic() // JWT token을 사용하므로 basic 인증 disable
                .disable()
                .csrf() // csrf 비활성화
                .disable()
                .sessionManagement()  // session 을 사용하지 않음
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeHttpRequests()
                .requestMatchers(FRONT_URL + "/main/**").permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .exceptionHandling() // 예외 처리
                .authenticationEntryPoint(new CustomAuthenticationEntryPoint())
                .and()
                .formLogin() // form login disable
                .disable()
                .addFilter(corsFilter) // @CrossOrigin(인증X), 시큐리티 필터에 등록 인증(O)
                .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class) // JWT 필터 등록
                .build();
    }
}

코드가 매우 긴데 중요한 부분만 따로 보자.

  • @EnableWebSecurity : Spring Security 설정을 활성화하기 위한 어노테이션이다. 웹 보안 관련 기능을 활성화하는데 사용된다.

  • .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class) : JWT 필터를 UsernamePasswordAuthenticationFilter 뒤에 추가 한다.

  • UsernamePasswordAuthenticationFilter

UsernamePasswordAuthenticationFilterSpring Security 에서 제공하는 필터 중 하나로, 사용자의 이름과 비밀번호를 사용하여 인증을 수행한다. 이 필터는 일반적으로 폼 기반 로그인을 처리할 때 사용된다. 사용자가 로그인 폼을 통해 자신의 이름과 비밀번호를 제출하면, 이 필터가 해당 정보를 받아 인증 과정을 수행한다.

  • JwtRequestFilter 와 필터 순서

JWT 기반 인증 방식에서는 폼 로그인을 사용하지 않으므로, UsernamePasswordAuthenticationFilter 가 인증을 처리하기 전에 JWT 토큰을 먼저 검증하는 것이 중요하다. 그래서 addFilterBefore 를 사용하여 Jwt 필터가 UsernamePasswordAuthenticationFilter 보다 먼저 실행되게 순서를 지정해 주었다.

5. JWT Filter 예외 처리

@Override
protected void doFilterInternal(HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException {
    try {
        final String jwtHeader = request.getHeader(HEADER_STRING);
        log.info("JWT Filter 진입");
        if (pathMatchesExcludePattern(request.getRequestURI())) {
            filterChain.doFilter(request, response);
            return;
        }

        if (jwtHeader == null || jwtHeader.isEmpty()) {
            request.setAttribute("exception", JwtErrorCode.NOTFOUND_TOKEN);
            throw new JwtFilterException(JwtErrorCode.NOTFOUND_TOKEN);
        }

        if (!jwtHeader.startsWith(TOKEN_PREFIX)) {
            request.setAttribute("exception", JwtErrorCode.UNSUPPORTED_TOKEN);
            throw new JwtFilterException(JwtErrorCode.UNSUPPORTED_TOKEN);
        }

        String token = jwtHeader.replace(TOKEN_PREFIX, "");
        request.setAttribute("userCode", JWT.require(Algorithm.HMAC512(SECRET)).build().verify(token).getClaim("id").asLong());
    } catch (TokenExpiredException e) {
        request.setAttribute("exception", JwtErrorCode.EXPIRED_TOKEN);
        throw new JwtFilterException(JwtErrorCode.EXPIRED_TOKEN);
    } catch (JWTVerificationException e) {
        request.setAttribute("exception", JwtErrorCode.WRONG_TYPE_TOKEN);
        throw new JwtFilterException(JwtErrorCode.WRONG_TYPE_TOKEN);
    } catch (JwtFilterException e) {
        filterChain.doFilter(request, response);
        return;
    }
    filterChain.doFilter(request, response);
}

doFiletInternal 을 오버라이딩한 코드에서 예외가 발생하면 request.setAttribute("exception", JwtErrorCode.NOTFOUND_TOKEN); 이렇게 request 에 헤더를 exception 으로 값은 커스텀 ErrorCode 를 넘겨주는 걸 볼 수 있다. 또한 JwtFilterException 에러를 던지면 밑에서 JwtFilterException 에러를 잡아서 바로 다음 필터로 넘겨주고 return 한다.

왜 예외를 던져서 @RestControllerAdvice 에서 전역적으로 예외 처리를 하지 않는 것 일까?

@RestControllerAdvice에 대한 정보는 이 링크의 글을 읽어보자

왜 스프링 시큐리티 예외는 @ControllerAdvice 에서 처리할 수 없을까?

일반적으로 예외는 클라이언트 측에서 서버로 보낸 요청을 애플리케이션의 컨트롤러가 받은 후 요청에 대한 비즈니스 로직을 처리하는 과정에서 발생한다. 즉, 일단 요청이 컨트롤러에 도달한 다음에 예외가 발생하는 것이다.

하지만 스프링 시큐리티는 요청이 컨트롤러에 도달하기 전에 필터 체인 에서 예외를 발생시킨다. 앞서 이야기했듯이 @ControllerAdvice 는 컨트롤러 계층에서 발생하는 예외를 처리하는데, 요청이 컨트롤러에 도달하기도 전에 이미 예외가 발생해서 요청이 컨트롤러에 도달하지도 못했기 때문에 @ControllerAdvice 에서 처리를 할 수가 없다.

AuthenticationEntryPoint

스프링 시큐리티에서는 사용자가 인증되지 않았거나 AuthenticationException 이 발생했을 때 AuthenticationEntryPoint 에서 예외 처리를 시도한다. 따라서 AuthenticationEntryPoint 의 구현체를 적절하게 이용하면 된다.

출처

Custom JwtErrorCode

@Getter
public enum JwtErrorCode {
    NOTFOUND_TOKEN(400, "Authorization이 없습니다."),
    UNSUPPORTED_TOKEN(400, "Bearer로 시작하지 않습니다."),
    EXPIRED_TOKEN(400, "토큰이 만료되었습니다."),
    WRONG_TYPE_TOKEN(400, "유효하지 않은 토큰입니다.");

    private int code;
    private String message;

    JwtErrorCode(int status, String message) {
        this.code = status;
        this.message = message;
    }
}

먼저 에러 코드를 사용해서 에러를 관리하기 쉽게 Enum 으로 정의해둔다.

예외 발생시

JwtRequestFilter 에서 JWT Token 검증 시 예외 발생 코드를 보자.

if (jwtHeader == null || jwtHeader.isEmpty()) {
	request.setAttribute("exception", JwtErrorCode.NOTFOUND_TOKEN);
    throw new JwtFilterException(JwtErrorCode.NOTFOUND_TOKEN);
}

예외가 발생하면 requestattributeexceptionJwtErrorCode 를 넣어주고 JwtFilterException 에러를 발생시킨다.

catch (JwtFilterException e) {
	filterChain.doFilter(request, response);
    return;
}

그럼 발생시킨 JwtFilterException을 밑에서 잡아서 예외를 발생시키지 않고 requestJwtFilterException 가 담긴채 다음 필터로 넘기고 return 한다.

위에서 throw new JwtFilterException(JwtErrorCode.NOTFOUND_TOKEN); 를 지우고 바로 다음 필터로 넘기고 return 해도 되지만 검증 로직이 많으므로 검증로직에 실패하면 에러를 던지고 이 에러를 처리하는 곳은 한 곳에서 관리하도록 에러를 던지고 받는 로직으로 구성하였다.

에외 처리

CustomAuthenticationEntryPoint

@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        Object exceptionObj = request.getAttribute("exception");
        String errorMessage = "인증 에러가 발생했습니다."; // 기본 에러 메시지

        if (exceptionObj instanceof JwtErrorCode jwtErrorCode) {
            setResponse(response, jwtErrorCode.getCode() + " : " + jwtErrorCode.getMessage());
        } else {
            setResponse(response, errorMessage);
        }
    }

    private void setResponse(HttpServletResponse response, String errorMessage) throws IOException {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter()
                .println("{\"errorMessage\": \"" + errorMessage + "\"}");
    }
}

AuthenticationEntryPoint 구현한 CustomAuthenticationEntryPoint 이다.

여기서는 Object exceptionObj = request.getAttribute("exception"); 를 통해 "exception" 에 들어가 있는 객체를 꺼내온다. 이 객체가 JwtErrorCode 의 자식이라면 클라이언트에게 보내는 응답을 커스텀한 JwtErrorCode 으로 구성하여 더 자세한 커스텀 에러 응답을 보내준다.

6. JwtService 구현

"Bearer 12313123..." 형식으로 된 JWT Token 을 복호화하고 암호화하는 서비스를 구현한다.

@Service
public class JwtService {

    public Long getUserIdByJWT(HttpServletRequest request) {
        String jwtHeader = request.getHeader(HEADER_STRING);
        String token = jwtHeader.replace(TOKEN_PREFIX, "");
        return JWT.require(Algorithm.HMAC512(SECRET)).build().verify(token).getClaim("id").asLong();
    }

    public String createJWTToken(String email, Long userId, String name) {
        return JWT.create()
                .withSubject(email)
                .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .withClaim("id", userId)
                .withClaim("nickname", name)
                .sign(Algorithm.HMAC512(SECRET));
    }
}
public String createJWTToken(String email, Long userId, String name) {
	return JWT.create()
    	.withSubject(email)
        .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
        .withClaim("id", userId)
        .withClaim("nickname", name)
        .sign(Algorithm.HMAC512(SECRET));
}
  • .withSubject(email) : JWT의 주제를 설정한다. 사용자의 이메일 주소를 주제로 사용하였다.

  • .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) : 토큰의 만료 시간을 설정한다.

  • .withClaim("id", userId) .withClaim("nickname", name) : 토큰에 포함할 추가 정보를 설정한다. 사용자 ID 와 name 을 추가하였다.

  • .sign(Algorithm.HMAC512(SECRET)); : 토큰에 서명을 추가한다. 비밀키를 기반으로 HMAC512 알고리즘으로 서명한다. 서명은 토큰이 변경되지 않았음을 검증하는데 사용한다.

public Long getUserIdByJWT(HttpServletRequest request) {
	String jwtHeader = request.getHeader(HEADER_STRING);
    String token = jwtHeader.replace(TOKEN_PREFIX, "");
    return JWT.require(Algorithm.HMAC512(SECRET)).build().verify(token).getClaim("id").asLong();
}
  • String jwtHeader = request.getHeader(HEADER_STRING); : Authorization 헤더의 값인 Bearer 12313123..."을 가져온다.

  • String token = jwtHeader.replace(TOKEN_PREFIX, ""); : Bearer 12313123..." 에서 앞의 Berer 부분을 없애주고 순수한 토큰 값만 대입한다.

  • JWT.require(Algorithm.HMAC512(SECRET)).build() : 설정한 SECRET 값을 사용하여 HMAC512 알고리즘으로 서명된 JWT를 검증할 준비를 한다.

  • .verify(token).getClaim("id").asLong(); : 토큰 값을 검증하여 id 에 지정된 값을 Long 타입으로 가져온다.

7. UserService에서 JwtService 사용

public UserDto getCurrentUser(HttpServletRequest request) {
    Long userIdByJWT = jwtService.getUserIdByJWT(request);
    User user = userRepository.findById(userIdByJWT).orElseThrow(UserNotFoundException::new);
    return UserDto.builder()
            .profileImgUrl(user.getProfileImgUrl())
            .nickname(user.getNickname())
            .email(user.getEmail())
            .provider(user.getProvider())
            .userRole(user.getUserRole())
            .description(user.getDescription())
            .createTime(user.getCreateTime())
            .build();
}

UserService 코드에서 jwtService 를 사용하는 코드이다.

jwtService 를 이용해서 request 에 담긴 JWT Token 값을 userId 값으로 복호화한다.


profile
가오리의 개발 이야기

0개의 댓글