스프링 시큐리티 구현
스프링 시큐리티와 관련된 설정 방법에 대해 알아보겠습니다.
SecurityConfiguration 구현
SecurityConfiguration 클래스 [HttpSecurity]
@Configuration
@RequiredArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final JwtTokenProvider jwtTokenProvider;
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.httpBasic().disable()
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeHttpRequests()
.antMatchers("/sign-api/sign-in", "/sign-api/sign-up",
"/sign-api/exception").permitAll()
.antMatchers(HttpMethod.GET, "/product/**").permitAll()
.antMatchers("**exception**").permitAll()
.anyRequest().hasRole("ADMIN")
.and()
.exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler())
.and()
.exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint())
.and()
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider),
UsernamePasswordAuthenticationFilter.class);
}
}
- HttpSecurity를 설정하는 Configure 메서드이고, 스프링 시큐리티의 설정은 대부분 HttpSecurity를 통해 진행이 된다
- HttpSecurity의 대표적인 기능
- 리소스 접근 권한 설정
- 인증 실패 시 발생하는 예외 처리
- 인증 로직 커스터마이징
- csrf, cors 등의 스프링 시큐리티 설정
- configure 메서드에 작성되어 있는 코드의 설정별 설명
- httpBasic( ).disable( )
- UI를 사용하는 것을 기본 값으로 가진 시큐리티의 설정을 비활성화 한다.
- csrf( ).disable( )
- REST API에서는 CSRF 보안이 필요 없기 때문에 비활성화 하는 로직이다.
- 스프링 시큐리티에의 csrf( ) 메서드는 기본적으로 CSRF 토큰을 발급해서 클라이언트로부터 요청을 받을 때마다 토큰을 검증하는 방식으로 동작한다.
- 브라우저 사용 환경이 아니라면 비활성화해도 크게 문제가 되지 않는다.
- sessionManagement( ).sessionCreationPolicy(SessionCreationPolicy.STATELESS)
- REST API 기반의 애플리케이션의 동작 방식을 설정
- 현재 프로젝트에서는 JWT 토큰으로 인증 처리하며, 세션은 사용하지 않기에 STATELESS로 설정한다.
- authorizeRequest( )
- 애플리케이션에 들어오는 요청에 대한 사용 권한을 체크한다.
- antMatchers( ) 메서드는 antPattern을 통해 권한을 설정하는 역할을 한다.
- "/sign-api/sign-in", "/sign-api/sign-up", "/sign-api/exception" 경로에 대해서는 모두에게 허용한다.
- "/product" 로 시작하는 경로의 GET 요청은 모두 허용한다
- "exception" 단어가 들어간 경로는 모두 허용한다.
- 기타 요청은 인증된 권한을 가진 사용자에게 허용한다.
- exceptionHandling( ).accessDeniedHandler( )
- 권한을 확인하는 과정에서 통과하지 못하는 예외가 발생할 경우 예외를 전달한다.
- exceptionHandling( ).auithenticationEntryPoint( )
- 인증 과정에서 예외가 발생할 경우 예외를 전달한다.
- addFilterBefore( )
- 어느 필터 앞에 추가할 것인지 설정
- 현재의 설정은 스프링 시큐리티에서 인증을 처리하는 필터인 UsernamePasswordAuthenticationFilter 앞에 기존에 생성했던 JwtAuthenticationFitler를 추가하겠다는 의미이다.
- httpBasic( ).disable( )
SecurityConfiguration 클래스 [WebSecurity]
@Configuration
@RequiredArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final JwtTokenProvider jwtTokenProvider;
//** 생략
@Override
public void configure(WebSecurity webSecurity) {
webSecurity.ignoring().antMatchers("/v2/api-docs", "/swagger-resources/**",
"/swagger-ui.html","/webjars/**", "/swagger/**", "sign-api/exception");
}
}
- WebSecurity는 HttpSecurity 앞단에 적용되며, 전체적으로 스프링시큐리 영향권 밖에 있다.
- 즉, 인증과 인가가 모두 적용되기 전에 동작하는 설정이다.
- 다양한 곳에서 사용되지 않고 인증과 인가가 적용되지 않는 리소스 접근에 대해서만 사용한다.
- [예시] Swagger에 적용되는 인증과 인가를 피하기 위해 ignoring( ) 메서드를 사용하여 Swagger 관련 경로에 대한 예외 처리를 수행한다.(인증과 인가를 무시하는 경로로 설정한 것이다)
커스텀 AccessDeniedHandler, AuthenticationEntryPoint 구현
CustomAccessDeniedHandler 클래스
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
private final Logger LOGGER = LoggerFactory.getLogger(CustomAccessDeniedHandler.class);
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException)
throws IOException {
LOGGER.info("[handle] 접근이 막혔을 경우 경로 리다이렉트");
response.sendRedirect("/sign-api/exception");
}
}
- 기본적으로 handle( ) 메서드를 오버라이딩 하여 구현한다.
- AccessDeniedException 은 엑세스 권한이 없는 리소스에 접근할 경우 발생하는 예외이다.
- 예외를 처리하기 위해 AccessDeniedHandler 인터페이스가 사용되고,SecurityConfiguration에 exceptionHandling( ) 메서드를 통해 추가하였다.
- 예시로 response 에서 리다이렉트하는 sendRedirect( ) 메서드를 활용하는 방식으로 구현이 되었다.
CustomAuthenticationEntryPoint 클래스
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 {
ObjectMapper objectMapper = new ObjectMapper();
LOGGER.info("[commence] 인증 실패로 response.sendError 발생");
EntryPointErrorResponse errorResponse = new EntryPointErrorResponse();
errorResponse.setMsg("인증에 실패하였습니다.");
response.setStatus(401);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().write(objectMapper.writeValueAsString(errorResponse));
}
}
- commence( ) 메서드는 httpServletRequest, HttpServletResponse, AuthenticationException을 매개변수로 받는다.
- 해당 예시는 예외 처리를 위해 리다이렉트가 아니라 직접 Response를 생성해서 클라이언트에게 응답받는 방식이다.
- 직접 Response 를 생성해서 클라이언트에게 응답하는 방식으로 구현되어 있다
- 메시지를 담기 위해 EntryPointErrorResponse 객체를 만들어 메시지를 설정
- response 에 상태 코드(status)와 콘텐츠 타입(content-type) 등을 설정
- ObjectMapper를 사용하여 EntryPointErrorResponse 객체를 바디 값으로 파싱한다.
EntryPointErrorResponse 클래스
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class EntryPointErrorResponse {
private String msg;
}
CustomAuthenticationEntryPoint 클래스 [응답 코드 설정]
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 {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
- commence( ) 메서드 내부에 인증 실패 코드만 전달하는 방식이다.
반응형
'Book > 스프링부트 핵심가이드' 카테고리의 다른 글
스프링 시큐리티(Spring Security) 구현(of. 회원가입, 로그인) (0) | 2023.12.08 |
---|---|
스프링 시큐리티(Spring Security) 구현(of. Jwt Token) (1) | 2023.12.06 |
스프링 시큐리티(Spring Security)와 JWT (2) | 2023.12.05 |
댓글