inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

doFilterInternal 관련 질문있습니다.

1036

박정훈

작성한 질문수 24

0

안녕하세요. 제가 BasicAuthenticationFilter 상속받아서 doFilterInternal 메소드를 구현했는데 해당 필터의 해당 메소드는 인증이나 권한이 필요한 API를 호출했을 때만 동작을 하는 걸로 알고 있었는데 SecurityConfig에서 antMatcher에 permitAll로 지정한 경로의 API를 호출했는데 doFilterInternal 메소드가 동작하는 현상이 발생하는데 혹시 왜그런건지 궁금합니다. 해당부분에 관련된 코드는 아래와 같습니다.

SecurityConfig

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final CorsConfig corsConfig;
    private final MemberRepository memberRepository;
    private final JwtProvider jwtProvider;

    public SecurityConfig(CorsConfig corsConfig, MemberRepository memberRepository, JwtProvider jwtProvider) {
        this.corsConfig = corsConfig;
        this.memberRepository = memberRepository;
        this.jwtProvider = jwtProvider;
    }

    @Bean
    BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        return http
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .formLogin().disable()
                .httpBasic().disable()
                .apply(new MyFilters())
                .and()
                .authorizeRequests()
                .antMatchers("/api/member/join").permitAll()
                .antMatchers("/api/member/login").permitAll()
                .anyRequest().authenticated()
                .and().build();
    }

    public class MyFilters extends AbstractHttpConfigurer<MyFilters, HttpSecurity> {

        @Override
        public void configure(HttpSecurity builder) throws Exception {
            AuthenticationManager authenticationManager = builder.getSharedObject(AuthenticationManager.class);
            builder
                    .addFilter(corsConfig.corsFilter())
                    .addFilter(new JwtAuthenticationFilter(authenticationManager, jwtProvider))
                    .addFilter(new JwtAuthorizationFilter(authenticationManager, memberRepository, jwtProvider));
        }
    }
}

 

JwtAuthenticationFilter

package com.example.shop.jwt;

import com.example.shop.auth.PrincipalDetails;
import com.example.shop.model.Member;
import com.example.shop.repository.MemberRepository;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.crypto.SecretKey;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

    private final MemberRepository memberRepository;
    private final JwtProvider jwtProvider;

    public JwtAuthorizationFilter(AuthenticationManager authenticationManager, MemberRepository memberRepository, JwtProvider jwtProvider) {
        super(authenticationManager);
        this.memberRepository = memberRepository;
        this.jwtProvider = jwtProvider;
    }

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

        String refreshToken = jwtProvider.getRefreshTokenInCookie(request);
        String accessToken = "";
        SecretKey jwtKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(JwtProperties.SECRET));

        if (refreshToken == null) {
            chain.doFilter(request, response);
            return;
        }

        String jwtHeader = request.getHeader(JwtProperties.HEADER_STRING);

        Claims claims = null;

        try { // refreshToken 유효성 검증
            jwtProvider.validRefreshToken(refreshToken);
        } catch (Exception e) { // refreshToken 검증 결과에 따른 예외처리
            e.printStackTrace();
            chain.doFilter(request, response);
            return;
        }

        Member member = memberRepository.findByRefreshToken(refreshToken);
        Long memberId = member.getId();

        try {
            if (jwtHeader == null) { // 브라우저 새로고침 고려하여 accessToken 재발급
                accessToken = jwtProvider.createAccessToken(memberId, jwtKey);
                response.addHeader(JwtProperties.HEADER_STRING, accessToken);
            } else { // 그 외의 경우 accessToken 유효성 검증
                accessToken = jwtHeader.replace(JwtProperties.AUTH_TYPE, "");
                claims = Jwts.parserBuilder().setSigningKey(JwtProperties.SECRET).build()
                        .parseClaimsJws(accessToken).getBody();
            }
        } catch (Exception e) { // accessToken 검증 결과에 따른 예외처리
            e.printStackTrace();
            chain.doFilter(request, response);
            return;
        }

        // refreshToken, accessToken 검증 이후 작업
        PrincipalDetails principalDetails = new PrincipalDetails(member);

        Authentication authentication = new UsernamePasswordAuthenticationToken(principalDetails, null, principalDetails.getAuthorities());

        SecurityContextHolder.getContext().setAuthentication(authentication);

        chain.doFilter(request, response);
    }
}

 

특이한 점은 api/member/login 경로의 API(UsernamePasswordAuthenticationFilter의 attemptAuthentication를 상속받아 구현했습니다.)를 호출했을 때에는 doFilterInternal이 동작을 하지 않지만 api/member/join 경로의 API를 호출했을 때에는 doFilterInternal이 동작을 합니다.

웹앱 JPA spring-boot java spring

답변 1

0

김영한

안녕하세요. 정훈님 죄송하지만 질문 안내에 있는 것 처럼 강의 학습에 관련된 질문을 올려주시길 부탁드립니다.

저도 마음으로는 도움을 드리고 싶지만, 하루에도 수 많은 분들이 질문을 올려주십니다. 그래서 강의 학습과 관련된 질문에 초점을 맞추는 것이 맞다 생각합니다. 다시한번 이해를 부탁드립니다.

 

0

박정훈

네 알겠습니다. 감사합니다.

OrderServiceTest 상문주문 테스트 시 update 쿼리 문의

0

23

1

sdk 설정 오류

0

59

2

오탈자 - @Transactional

0

58

1

src/test/resources 테스트 경로 문제

0

54

1

상품 등록후 H2 db 출력 순서 바꿀 수 있나요?

0

67

1

MemberRepositoryTest 실행오류

0

83

1

boot 4.x >>> trasasction rolled back log & p6spy(영한님, 수업 자료 업데이트 해주시면 감사하겠습니다!!)

1

187

2

강의 마지막 QueryDSL 사용 부분 질문있습니다

1

146

2

클라이언트에서 isbn과 author 수정 요청을 한 경우에 대해 질문드립니다.

0

54

1

도메인 모델 패턴 vs 트랜잭션 스크립트 패턴

0

77

1

기본 생성자

0

62

1

h2 DB 연결시 jdbc url 변경 이유가 궁금합니다.

0

104

1

멤버서비스테스트 부분에서 막힙니다.

0

168

4

실무에서도 EntityManager를 이용해서 많이 작업하는 편일까요?

0

118

1

초반에 h2 다운로드 과정 꼭 필요한가요?

0

122

2

자신 필드에도 get으로 접근하는 이유가 있을까요?

0

115

1

24분 27초 연관관계 편의 메서드 위치

0

114

1

단건 주문만 가능하게 한건 의도한 부분이신가요?

0

112

2

빌드 툴, Gradle

0

61

1

h2연결은 된 것 같은데 엔티티 테이블까지 작성 후 확인해보아도 테이블이 안보입니다

0

78

2

Repository에서 EntityManager 주입 방식 차이

0

91

1

롬복과 사용자 정의 setter 메서드

0

74

1

주문 목록 조회 fetch join 질문드립니다

0

85

1

dirty checking 질문드립니다.

0

84

1