일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- Postman
- Lombok
- gradle
- appleM1
- restful api
- K8S
- DB생성
- Seek_Keyset
- spring
- wappalyzer
- String
- intellij
- CloutNative
- windows10
- VUE
- MySQL시작하기
- frontend
- SpringBoot
- MYSQL에러
- offset
- MySQL
- minikube
- 우분투에war배포
- Java
- 스프링에러
- 이클립스
- SQL
- springMVC
- NullPointerException
- pagination
- Today
- Total
미운 오리 새끼의 우아한 개발자되기
[Spring Boot] Spring Security 에서 특정 URL만 제외하여 필터링하기 본문
[Spring Boot] Spring Security 에서 특정 URL만 제외하여 필터링하기
Serina_Heo 2023. 1. 1. 11:14제목은 특정 URL 만 제외하여 필터링하기라고 썼지만..
내가 쓴 방법은 일단 Filter에는 들어가는데 Filter 안에 로직을 타지 않도록 하여 Servlet Container 로 넘기는 방법이다.
Spring 의 구조는 이러하다.
나의 경우에는 JWT 로 인증/인가를 하고 있어서 JWT Filter 를 두었고, JWT 안에 있는 사용자 정보를 Controller 에서 추출하여 사용하고 싶어서 Spring Security 를 적용하였다.
내가 현재 만들고 있는 API 중에 /notifications 로 시작하는 endpoint 가 있다.
/notifications
GET -- /{code}
POST -- /{code}
GET -- /count
이렇게 3개의 endpoint 가 있는데 마지막 /count 를 제외하고는 JWT Filter를 타서 사용자 정보를 SecurityContext 에 저장해주어야 한다는 것.
package com.hooonk.api.config;
import com.hooonk.api.config.filter.JwtAuthenticationFilter;
import com.hooonk.api.service.FirebaseService;
import com.hooonk.api.util.JwtTokenUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
JwtAuthenticationFilter jwtAuthenticationFilter(JwtTokenUtil jwtTokenUtil, FirebaseService firebaseService) {
return new JwtAuthenticationFilter(jwtTokenUtil, firebaseService);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http, JwtTokenUtil jwtTokenUtil, FirebaseService firebaseService) throws Exception {
return http
.httpBasic().disable()
.csrf().disable()
.cors().disable()
.authorizeRequests()
.antMatchers(
"/swagger-resources/**",
"/swagger-ui.html",
"/swagger-ui/index.html",
"/v3/api-docs",
"/webjars/**").permitAll()
.antMatchers("/health/check").permitAll()
.anyRequest().authenticated()
.and()
.requestMatchers().antMatchers("/account/**", "/notifications/**").and()
.addFilterBefore(jwtAuthenticationFilter(jwtTokenUtil, firebaseService), BasicAuthenticationFilter.class)
.build();
}
}
위와 같이 requestMathers().antMatchers("/account/**", "/notifications/**").and().addFilter ~~
이렇게 처리하니까 notifications 으로 시작하는 모든 API 는 jwt Filter 를 탈수 밖에 없었다.
그렇다고 /notifications 에 속한 endpoints 중에 필요한 녀석만 써주자니 pathVariable 이 있어서 endpoint 를 특정할 수도 없다.
그래서 JWT Filter 에서 HttpServletRequest의 Servlet Path를 가져와서 JWT Filter 내부의 로직을 타지 않게 if else 문으로 처리하였다.
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Authentication authentication;
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
try {
String path = req.getServletPath();
log.info("servletPath : " + path);
if(!path.contains("/notifications/count")) {
log.info("Don't pass here!!!!!!!!!!!!!!!!!!!!!!!!!!");
String authToken = req.getHeader("Authorization");
String bearerToken = authToken.substring(7);
String userEmail = firebaseService.getUserUid(bearerToken);
authentication = jwtTokenUtil.authenticate(new UsernamePasswordAuthenticationToken(userEmail, AuthorityUtils.createAuthorityList("USER")));
log.info("authentication.getPrincipal().toString() ==> " + authentication.getPrincipal().toString());
log.info("authentication.isAuthenticated() ==> " + authentication.isAuthenticated());
SecurityContextHolder.getContext().setAuthentication(authentication);
}
log.info("이거지");
chain.doFilter(request, response);
} // catch문 이하 생략 ~~
그랬더니 if else 에 통과는 하는데.. 403 Forbidden 에러가 나는것...-_-?
띠껍게도 IDE Console에는 Error log 가 보이지 않는데 왜!! 403 이 뜨는거지??
2023-01-01 10:54:12.922 TRACE 49978 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : "ERROR" dispatch for GET "/v1/error", parameters={}, headers={masked} in DispatcherServlet 'dispatcherServlet'
2023-01-01 10:54:12.925 TRACE 49978 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : 2 matching mappings: [{ [/error]}, { [/error], produces [text/html]}]
2023-01-01 10:54:12.925 TRACE 49978 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
2023-01-01 10:54:12.931 TRACE 49978 --- [nio-8080-exec-1] o.s.web.method.HandlerMethod : Arguments: [FirewalledRequest[ org.apache.catalina.core.ApplicationHttpRequest@5952c7a4]]
2023-01-01 10:54:12.939 DEBUG 49978 --- [nio-8080-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/json, application/*+json]
2023-01-01 10:54:12.940 TRACE 49978 --- [nio-8080-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Writing [{timestamp=Sun Jan 01 10:54:12 KST 2023, status=403, error=Forbidden, path=/v1/notifications/count}]
2023-01-01 10:54:12.957 TRACE 49978 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : No view rendering, null ModelAndView returned.
2023-01-01 10:54:12.957 DEBUG 49978 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Exiting from "ERROR" dispatch, status 403, headers={masked}
이거저거 해보다가 Spring Security Configuration의 FilterChain에 이걸 추가하니까 정상 작동 하였다.
.antMatchers("/notifications/count").permitAll()
내가 구현한 JWT Filter 는 GenericFilter 를 extends 하여 구현한 거지만,
아마도..? 구현하지 않은 다른 필터들을 거칠 때
permitAll 을 주지 않은 다른 request 들은 아래 구문에서 막힌게 아닌가 싶다.
.anyRequest().authenticated()
이번에 API 를 만들면서 Filter 와 Spring Security 를 좀 더 자세히 알게된 것 같다.
'Spring & Spring Boot > Spring Boot' 카테고리의 다른 글
[QueryDsl] querydsl 설정 (0) | 2022.11.24 |
---|---|
[Spring Boot] Cloud Native Java - 애플리케이션 마이그레이션 (1) (0) | 2022.09.29 |
[Spring Boot] Cloud Native Java - Test(3) 스프링 클라우드 컨트랙트 (0) | 2022.09.29 |
[Spring Boot] Cloud Native Java - Test(2) 슬라이스 - @RestClientTest (0) | 2022.09.28 |
[Spring Boot] Cloud Native Java - Test(2) 슬라이스 - @DataJpaTest (0) | 2022.09.28 |