Gateway Spring Security 공부 및 고민 내용 - nhnacademy-be10-WannaB/wannab-wiki GitHub Wiki
@RequiredArgsConstructor
@Controller
public class AuthController {
private final AuthService authService;
@PostMapping("/asd")
public ResponseEntity<Void> login() {
LoginRequest loginRequest = new LoginRequest("dang", "aaaa1111@");
LoginResponse response = authService.login(loginRequest);
ResponseCookie accessCookie = CookieUtils.createCookie("access_token", response.accessToken(), Duration.ofMinutes(30), false);
ResponseCookie refreshCookie = CookieUtils.createCookie("refresh_token", response.refreshToken(), Duration.ofDays(7), true);
return ResponseEntity.ok()
.header(HttpHeaders.SET_COOKIE, accessCookie.toString())
.header(HttpHeaders.SET_COOKIE, refreshCookie.toString())
.build();
}
}
- 요청을 보내는 방법은 authService.login 메서드를 사용함
@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {
private final AuthClient authClient;
@Override
public LoginResponse login(LoginRequest request) {
ResponseEntity response = authClient.login(request);
LoginResponse tokenDto = (LoginResponse) response.getBody();
return tokenDto;
}
}
@FeignClient(name = "gateway", url = "localhost:8081")
public interface AuthClient {
@PostMapping("/user-service/api/auth/login")
ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request);
}
- 이 요청시에는 당연히 accesstoken, refreshtoken이 없음
- 일단 Gateway에서 로그가 찍히는 걸 보니, Gateway의 필터까지는 무조건 옴
- 당연히 글로벌필터로 설정했으니 요청이 들어옴
- login 요청은 허용해줘야할듯?
- 일단 Cloud Document를 보면
[Spring Cloud Train Reference Documentation :: Spring Cloud Release](https://docs.spring.io/spring-cloud-release/reference/2023.0/index.html)
[Spring Cloud Gateway :: Spring Cloud Gateway](https://docs.spring.io/spring-cloud-gateway/reference/4.1/)
- 이부분은 나중에 추가 고민해보고
로그인과 회원가입 시에는 jwt가 없기 때문에 예외 처리를 해줘야 한다.
RouteValidator
@Component
public class RouteValidator {
public static final List<String> openApiEndpoints = List.of(
"/eureka",
"/coupon/api/v1/coupon/issued-check/",
"/auth/api/register",
"/auth/api/login"
);
public Predicate<ServerHttpRequest> isSecured =
request -> openApiEndpoints
.stream()
.noneMatch(uri -> request.getURI().getPath().contains(uri));
}
- openApiEndpoints에 지정하고 싶은 경로를 설정해주면 되는데
- 예를 들어 쿠폰 api의 모든 요청을 열어두고 싶으면
- /coupon/api/**이 아닌
- /coupon/api/ 이렇게 해줘야 한다.
AuthenticationFilter
// Global Filter 적용
@Component
@Slf4j
public class AuthenticationFilter extends AbstractGatewayFilterFactory<AuthenticationFilter.Config> {
@Autowired
private RouteValidator validator;
@Autowired
private JwtUtil jwtUtil;
public AuthenticationFilter() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
// pre
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
if (validator.isSecured.test(request)) {
// JWT 검증 로직
List<String> authHeaders = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
if (authHeaders == null || authHeaders.isEmpty()) {
throw new MissingAuthorizationHeaderException();
}
String authHeader = authHeaders.get(0);
if (authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
try {
jwtUtil.validateToken(token);
} catch (Exception e) {
throw new UnauthorizedAccessException();
}
} else {
throw new InvalidAuthorizationHeaderFormatException();
}
}
// post
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
ServerHttpResponse response = exchange.getResponse();
log.info("Custom Post filter: response code: " + response.getStatusCode());
}));
};
}
@Data
public static class Config {
private String baseMessage;
private boolean preLogger;
private boolean postLogger;
}
}
흠…
[[SpringBoot] Spring Cloud Gateway Authentication 문제](https://gose-kose.tistory.com/27)
- 이거 참고한건데 공부하다보니 깨달은건 결국..
- 그래서.. 선택을 해야함
- Spring Security + Spring Cloud Gateway + WebFlux 를 하던지
- Spring Cloud Gateway + JWT 의존성만으로 해결하던지
- 이거좋당
[토큰 인증과 권한체크를 Spring Cloud Gateway로 분리하기](https://yooyouny.tistory.com/38)
[인증? 인가? JWT 하나면 된다. (MSA 보안 쉽게 이해하기)](https://www.youtube.com/watch?v=KojezV-vDHQ&ab_channel=masiljangajji)
[Gateway, Spring Security, JWT 사용하여 인증 및 인가 처리하기](https://lincoding.tistory.com/120)
- Spring Security를 Reactive(비동기)방식으로 공부해야함
- 러닝 커브 높음
- Mono / Flux, WebFilter 등의 개념을 이해해야함
- 간단한 설정만으로도 검증로직을 구현할 수 있음
- 확장성은 높을듯
-
구현이 간단하긴하지
- Security 의존성 필요없고
- JWT 의존성만 땡겨오면 됨
- 그러면 화이트리스트를 만들어서 그 경로만 통과시켜주면 되겠네
[Spring Cloud Gateway security with JWT](https://medium.com/@rajithgama/spring-cloud-gateway-security-with-jwt-23045ba59b8a)
- 이사람 코드처럼 validate를 만들고 그걸기반으로 통과시키면 될듯?
-
가벼워서 쓰기 좋긴할듯?