클라이언트의 입장에서 스프링 시큐리티가 동작하는 상황에 대해 테스트 수행(Swagger 활용)
-> 접속 경로는 WebSecurity를 사용하는 configure() 메서드에서 인증에 대한 예외 처리 했기에 접속 가능
애플리케이션이 가동되면 스프링 시큐리티와 관련된 빈도 초기화되어 등록되면서 몇가지 로그 확인 가능
jwtTokenProvider
[2022-11-09 15:11:42.313] [INFO ][main] com.springboot.security.config.security.JwtTokenProvider [init] JwtTokenProvider 내 secretKey 초기화 시작
[2022-11-09 15:11:42.313] [INFO ][main] com.springboot.security.config.security.JwtTokenProvider [init] JwtTokenProvider 내 SecretKey 초기화 완료
jwtTokenProvider 클래스는 @Component로 등록돼 있고 @PostConstruct로 init() 메서드가 정의돼 있음
init() 메서드에서 properties에 정의되 있는 secretkey의 값을 가져와 인코딩 하는 작업 수행
DefaultSecurityFilterChain
[2022-35-09 15:35:08.923] [WARN ][main] org.springframework.security.config.annotation.web.builders.WebSecurity You are asking Spring Security to ignore Ant [pattern='/v2/api-docs']. This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.
[2022-35-09 15:35:08.923] [INFO ][main] org.springframework.security.web.DefaultSecurityFilterChain Will not secure Ant [pattern='/v2/api-docs']
[2022-35-09 15:35:08.923] [WARN ][main] org.springframework.security.config.annotation.web.builders.WebSecurity You are asking Spring Security to ignore Ant [pattern='/swagger-resources/**']. This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.
[2022-35-09 15:35:08.923] [INFO ][main] org.springframework.security.web.DefaultSecurityFilterChain Will not secure Ant [pattern='/swagger-resources/**']
[2022-35-09 15:35:08.923] [WARN ][main] org.springframework.security.config.annotation.web.builders.WebSecurity You are asking Spring Security to ignore Ant [pattern='/swagger-ui.html']. This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.
[2022-35-09 15:35:08.923] [INFO ][main] org.springframework.security.web.DefaultSecurityFilterChain Will not secure Ant [pattern='/swagger-ui.html']
[2022-35-09 15:35:08.923] [WARN ][main] org.springframework.security.config.annotation.web.builders.WebSecurity You are asking Spring Security to ignore Ant [pattern='/webjars/**']. This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.
[2022-35-09 15:35:08.923] [INFO ][main] org.springframework.security.web.DefaultSecurityFilterChain Will not secure Ant [pattern='/webjars/**']
[2022-35-09 15:35:08.923] [WARN ][main] org.springframework.security.config.annotation.web.builders.WebSecurity You are asking Spring Security to ignore Ant [pattern='/swagger/**']. This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.
[2022-35-09 15:35:08.923] [INFO ][main] org.springframework.security.web.DefaultSecurityFilterChain Will not secure Ant [pattern='/swagger/**']
[2022-35-09 15:35:08.923] [WARN ][main] org.springframework.security.config.annotation.web.builders.WebSecurity You are asking Spring Security to ignore Ant [pattern='/sign-api/exception']. This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.
[2022-35-09 15:35:08.923] [INFO ][main] org.springframework.security.web.DefaultSecurityFilterChain Will not secure Ant [pattern='/sign-api/exception']
[2022-11-09 15:11:42.600]
[INFO ][main] org.springframework.security.web.DefaultSecurityFilterChain Will secure any request with
[
org.springframework.security.web.session.DisableEncodeUrlFilter@28b47211,
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@4abb4041,
org.springframework.security.web.context.SecurityContextPersistenceFilter@6b3da23f,
org.springframework.security.web.header.HeaderWriterFilter@df34b01,
org.springframework.security.web.csrf.CsrfFilter@77185a2,
org.springframework.security.web.authentication.logout.LogoutFilter@43c64d6f,
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@17f7a1af,
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@742aa00a,
org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@247415be,
org.springframework.security.web.authentication.www.BasicAuthenticationFilter@377cc0f8,
org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5058fefb,
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@198a0416,
org.springframework.security.web.authentication.AnonymousAuthenticationFilter@48dc9950,
org.springframework.security.web.session.SessionManagementFilter@f31b991,
org.springframework.security.web.access.ExceptionTranslationFilter@cce672c,
org.springframework.security.web.access.intercept.FilterSecurityInterceptor@e280006
]
이는 SercurityFilterChain 인터페이스의 구현체 클래스
public final class DefaultSecurityFilterChain implements SecurityFilterChain {
private static final Log logger = LogFactory.getLog(DefaultSecurityFilterChain.class);
private final RequestMatcher requestMatcher;
private final List<Filter> filters;
public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) {
this(requestMatcher, Arrays.asList(filters));
}
public DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters) {
if (filters.isEmpty()) {
logger.info(LogMessage.format("Will not secure %s", requestMatcher));
} else {
logger.info(LogMessage.format("Will secure %s with %s", requestMatcher, filters));
}
this.requestMatcher = requestMatcher;
this.filters = new ArrayList(filters);
// 생략....
}
}
DefaultSecurityFilterChain은 HttpSecurity에 의해 호출되며, 생성자를 통해 사용될 Filter를 전달받음
@Override
public void configure(WebSecurity webSecurity){
webSecurity.ignoring().antMatchers("/v2/api-docs", "/swagger-resources/**",
"/swagger-ui.html", "/webjars/**", "/swagger/**", "/sign-api/exception");
}
앞서 정의한 SecurityConfiguration 클래스에서 설정한 WebSecurity를 활용하는 configure() 메서드에서 제외한 경로 표현
이후 앞서 보았던 DefaultSecurityFilterChain로그는 제외된 경로 외의 모든 요청에 대해 나열된 필터를 거친다는 것을 의미
정상적으로 회원가입 화면 출력 후 로그인 수행
로그인이 정상적으로 수행되었고 응답으로 온 토큰 값 또한 볼 수 있음
Swagger 페이지를 통한 상품 등록하기 위한 헤더 값 입력할 수 있는 폼 추가
@ApiImplicitParams({
@ApiImplicitParam(name = "X-AUTH-TOKEN", value = "로그인 성공 후 발급 받은 access_token",
required = true, dataType = "String", paramType = "header")
})
@PostMapping()
public ResponseEntity<ProductResponseDto> createProduct(@RequestBody ProductDto productDto){
ProductResponseDto productResponseDto = productService.saveProduct(productDto);
return ResponseEntity.status(HttpStatus.OK).body(productResponseDto);
}
create Product
비정상적인 동작 크게 두가지 -> 인증 실패, 인가 실패
인증과정 에서 예외 발생 경우
인증이 실패하여 CustomAuthenticationEntryPoint에 구현한 예외 상항에 대한 메세지가 담긴 응답이 애플리케이션에서 생서되고 클라이언트에게 전달되었음
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
private final Logger LOGGER = LoggerFactory.getLogger(CustomAuthenticationEntryPoint.class);
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
ObjectMapper objectMapper = new ObjectMapper();
LOGGER.info("[commence] 인증 실패로 response.sendError 발생");
EntryPointErrorResponse entryPointErrorResponse = new EntryPointErrorResponse();
entryPointErrorResponse.setMsg("인증이 실패하였습니다");
response.setStatus(401);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().write(objectMapper.writeValueAsString(entryPointErrorResponse));
}
}
인가 예외 상황
[2022-49-09 16:49:12.990] [INFO ][http-nio-8080-exec-8] com.springboot.security.config.security.JwtAuthenticationFilter [doFilterInternal] token 값 추출 완료. token : eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJmZHNhMTIzNCIsInJvbGVzIjpbIlJPTEVfVVNFUiJdLCJpYXQiOjE2Njc5ODAwODgsImV4cCI6MTY2Nzk4MzY4OH0.OsCBVrNSIX1MuOtpZwCpqA7RUrin80x2_VRHKg8Ik0c
[2022-49-09 16:49:12.990] [INFO ][http-nio-8080-exec-8] com.springboot.security.config.security.JwtAuthenticationFilter [doFilterInternal] token 값 유효성 체크 시작
[2022-49-09 16:49:12.990] [INFO ][http-nio-8080-exec-8] com.springboot.security.config.security.JwtTokenProvider [validateToken] 토큰 유효 체크 시작
[2022-49-09 16:49:12.993] [INFO ][http-nio-8080-exec-8] com.springboot.security.config.security.JwtTokenProvider [validateToken] 토큰 유효 체크 완료
[2022-49-09 16:49:12.993] [INFO ][http-nio-8080-exec-8] com.springboot.security.config.security.JwtTokenProvider [getAuthentication] 토큰 인증 정보 조회 시작
[2022-49-09 16:49:12.993] [INFO ][http-nio-8080-exec-8] com.springboot.security.config.security.JwtTokenProvider [getUsername] 토큰 기반 회원 구별 정보 추출
[2022-49-09 16:49:12.994] [INFO ][http-nio-8080-exec-8] com.springboot.security.config.security.JwtTokenProvider [getUsername] 토큰 기반 회원 구별 정보 추출 완료, info : fdsa1234
[2022-49-09 16:49:12.994] [INFO ][http-nio-8080-exec-8] com.springboot.security.service.impl.UserDetailsServiceImpl [loadUserByUsername] loadUserByUsername 수행. username : fdsa1234
[2022-49-09 16:49:13.002] [INFO ][http-nio-8080-exec-8] com.springboot.security.config.security.JwtTokenProvider [getAuthentication] 토큰 인증 정보 조회 완료, UserDetails UserName : fdsa1234
[2022-49-09 16:49:13.003] [INFO ][http-nio-8080-exec-8] com.springboot.security.config.security.JwtAuthenticationFilter [doFilterInternal] token 값 유효성 체크 완료
[2022-49-09 16:49:13.005] [INFO ][http-nio-8080-exec-8] com.springboot.security.config.security.CustomAccessDeniedHandler [handle] 접근이 막혔을 경우 경로 리다이렉트
[2022-49-09 16:49:13.009] [ERROR][http-nio-8080-exec-9] com.springboot.security.controller.SignController ExceptionHandler 호출, null, 접근이 금지되었습니다.
인증은 정상적으로 수행되었지만 인가가 실패해서 접근이 막힘
-> CustomAccessDeniedHandler에서 수행
com.springboot.security.service.impl.SignServiceImpl [getSignUpResult] userEntity 값이 들어왔는지 확인 후 결과 주입
com.springboot.security.service.impl.SignServiceImpl [getSignUpResult] 정상 처리 완료
com.springboot.security.controller.SignController [signUp] 회원가입을 완료했습니다. id : fdsa1515
com.springboot.security.config.security.JwtTokenProvider [resolveToken] HTTP 헤더에서 Token 값 추출
com.springboot.security.config.security.JwtAuthenticationFilter [doFilterInternal] token 값 추출 완료. token : null
com.springboot.security.config.security.JwtAuthenticationFilter [doFilterInternal] token 값 유효성 체크 시작
com.springboot.security.controller.SignController [signIn] 로그인을 시도하고 있습니다. id : fdsa1515, pw : ****
com.springboot.security.service.impl.SignServiceImpl [getSignInResult] signDataHandler로 회원 정보 요청
com.springboot.security.service.impl.SignServiceImpl [getSignInResult] Id : fdsa1515
com.springboot.security.service.impl.SignServiceImpl [getSignInResult] 패스워드 비교 수행
com.springboot.security.service.impl.SignServiceImpl [getSignInResult] 패스워드 일치
com.springboot.security.service.impl.SignServiceImpl [getSignInResult] SignInResultDto 객체 생성
com.springboot.security.config.security.JwtTokenProvider [createToken] 토큰 생성 시작
com.springboot.security.config.security.JwtTokenProvider [createToken] 토큰 생성 완료
com.springboot.security.service.impl.SignServiceImpl [getSignInResult] SignInResultDto 객체에 값 주입
com.springboot.security.controller.SignController [signIn] 정상적으로 로그인되었습니다. id : fdsa1515, token : eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJmZHNhMTUxNSIsInJvbGVzIjpbIlJPTEVfQURNSU4iXSwiaWF0IjoxNjY3OTgwNzUxLCJleHAiOjE2Njc5ODQzNTF9.x0UqFz5dpGSyt_msHSjVoyggMiZBNzX9_OzVYcO9jEQ
com.springboot.security.config.security.JwtTokenProvider [resolveToken] HTTP 헤더에서 Token 값 추출
com.springboot.security.config.security.JwtAuthenticationFilter [doFilterInternal] token 값 추출 완료. token : eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJmZHNhMTUxNSIsInJvbGVzIjpbIlJPTEVfQURNSU4iXSwiaWF0IjoxNjY3OTgwNzUxLCJleHAiOjE2Njc5ODQzNTF9.x0UqFz5dpGSyt_msHSjVoyggMiZBNzX9_OzVYcO9jEQ
com.springboot.security.config.security.JwtAuthenticationFilter [doFilterInternal] token 값 유효성 체크 시작
com.springboot.security.config.security.JwtTokenProvider [validateToken] 토큰 유효 체크 시작
com.springboot.security.config.security.JwtTokenProvider [validateToken] 토큰 유효 체크 완료
com.springboot.security.config.security.JwtTokenProvider [getAuthentication] 토큰 인증 정보 조회 시작
com.springboot.security.config.security.JwtTokenProvider [getUsername] 토큰 기반 회원 구별 정보 추출
com.springboot.security.config.security.JwtTokenProvider [getUsername] 토큰 기반 회원 구별 정보 추출 완료, info : fdsa1515
com.springboot.security.service.impl.UserDetailsServiceImpl [loadUserByUsername] loadUserByUsername 수행. username : fdsa1515
com.springboot.security.config.security.JwtTokenProvider [getAuthentication] 토큰 인증 정보 조회 완료, UserDetails UserName : fdsa1515
com.springboot.security.config.security.JwtAuthenticationFilter [doFilterInternal] token 값 유효성 체크 완료
com.springboot.security.service.impl.ProductServiceImpl [saveProduct productDTO : ProductDto(name=string, price=12, stock=132)
com.springboot.security.service.impl.ProductServiceImpl [saveProduct] saveProduct : Product(number=2, price=12, stock=132, createdAt=null, updatedAt=null)