Josh 성장일기

Spring Security + jwt 를 활용기에 대한 기록용 및 복습 포스트입니다.

 

- 초보개발자로써 혼자서 공부한 내용을 정리삼아 블로그에 작성하니 잘못된 점 바로잡아주시면 감사하겠습니다! -

 

저번 포스트에 이어 이번에는 HTTP Request 가 이루어졌을때 jwt 에 대한 Filter 기능을 구현해놓은 

JwtAuthenticationFilter 클래스에 대하여 알아보겠습니다.

 

JwtAuthenticationFilter 

@Component
@EnableWebSecurity
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter

 

먼저 JwtAuthenticationFilter 는 Spring의 Filter 기능을 통하여 컨트롤러에 도달하기전의 Filter 기능을 구현해야 합니다.

그러므로 OncePerRequestFilter 클래스를 상속받아 doFilterInternal 메서드에 대하여 @Override 합니다.

 

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

    // request 요청으로 header 안에 jwt 토큰을 보내온것을 받음
    final String authHeader = request.getHeader("Authorization");
    final String jwt;
    final String userEmail;
    if(authHeader == null || !authHeader.startsWith("Bearer")) {
        filterChain.doFilter(request, response);
        return;
    }
    jwt = authHeader.substring(7);
    userEmail = jwtService.extractUsername(jwt);

    // 헤더에 토큰이 담겨서 넣어왔지만 스프링 시큐리티에서 아직 인증되지 않은 사용자일경우
    if(userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
        UserDetails userDetails = userDetailsService.loadUserByUsername(userEmail);
        if(jwtService.isTokenValid(jwt, userDetails)) {
            UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                    userDetails,
                    null,
                    userDetails.getAuthorities()
            );
            authToken.setDetails(
                    new WebAuthenticationDetailsSource().buildDetails(request)
            );
            SecurityContextHolder.getContext().setAuthentication(authToken);
        }
        filterChain.doFilter(request, response);
    }
}

 

 

final String authHeader = request.getHeader("Authorization");

 

HTTP 통신이 이루어지게 되면서 인증에 대한 값은 HTTP Header 의 Authorization 에 인증여부를 담아서 보내주게 됩니다.

그리하여 먼저 HttpServletRequest request 파라미터에서 인증여부 값을 꺼내오게됩니다.

 

 

if(authHeader == null || !authHeader.startsWith("Bearer")) {
    filterChain.doFilter(request, response);
    return;
}

만약 authHeader 에 null 값으로 들어가있거나 Bearer 로 시작하지 않게 접근이 되었다면

filterChain.doFilter(request, response);

 메서드를 통하여 그 후에 Filter Chain 들을 수행하게 합니다.

 

 

jwt = authHeader.substring(7);
userEmail = jwtService.extractUsername(jwt);

authHeader 에 null 값이 아니고 Bearer 로 시작하여 접근되었다면 jwt 토큰값을 가져오고 

jwtService 인스턴스의 extractUsername 메서드를 활용하여 접근자의 userEmail 값을 가져옵니다.
※ JwtService 클래스에 대해서는 다음 포스팅때 올리도록 하겠습니다.

 

 

 

// 헤더에 토큰이 담겨서 넣어왔지만 스프링 시큐리티에서 아직 인증되지 않은 사용자일경우
if(userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
    UserDetails userDetails = userDetailsService.loadUserByUsername(userEmail);
    if(jwtService.isTokenValid(jwt, userDetails)) {
        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                userDetails,
                null,
                userDetails.getAuthorities()
        );
        authToken.setDetails(
                new WebAuthenticationDetailsSource().buildDetails(request)
        );
        SecurityContextHolder.getContext().setAuthentication(authToken);
    }
    filterChain.doFilter(request, response);
}

!!! 헤더에 토큰이 담겨서 왔지만 스프링 시큐리티에서 아직 인증되지 않은 사용자일 경우 !!!

 

UserDetails userDetails = userDetailsService.loadUserByUsername(userEmail);

ApplicationConfig @Configuration 어노테이션을 통해 userDetailService의 loadUserByUsername 메서드를 구현하여 @Bean => 스프링 빈으로 등록한 메서드를 호출하여 사용자의 디테일한 정보를 받아옵니다.

 

SecurityContextHolder.getContext().setAuthentication(authToken);

위의 userDetails 를 토대로 스프링 시큐리티에서 제공해주는 UsernamePasswordAuthenticationToken 클래스의 생성자를 통하여 authToken 을 생성후 SecurityComtextHolder 에 Authentication에 authToken을 set !!

 


위의 일련의 과정들을 통하여 스프링 시큐리티의 인증을 완료하게됩니다. 

아직 제가 많이 부족하여 설명이 부족하여 죄송합니다.. 

 

 

 

다음번 포스팅 때는 jwt 토큰에 대한 집중적인 서비스를 제공하는 JwtService 클래스에 대하여 복습하겠습니다.

감사합니다.

profile

Josh 성장일기

@JoshDev

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그