1. 개요
해커톤에 참여하느라 정리글이 늦었다.. 한 강의를 몇개월째 듣고있는건지.. 사실 진도는 거의 막바지 이지만, 강의 정리는 조금 느린 수준.. 그래서 다시 천천히 정리하기로 했다. 이번 글은 API gate-way의 인증 설정 즉 Filter의 구현과 Config service의 개념 정리이다.
2. 본문
- api-gateway filter 구현
처음에 api-gateway에 왜 fiter까지 구현을 하는거지? 라는 생각을 했다. 결국 user-service로 넘어가면 해당 서비스에서 구현한 filter에서 다시 검증과정을 거칠것이기 때문이다. 지금 차근 차근 정리해보니 조금은 다른 원리이다.
user-service: AuthenticationFilter
- login 로직 실행
- login 성공 시 Header에 token 추가
api-gateway: AuthorizationHeaderFilter
- header값 체크
- jwt 유효성 체크
나의 의문점은 "user-service단에 api-gateway에서 구현한 필터의 역할을 똑같이 구현해도 되지 않나?" 였다. 알고보니 아니었다... 일단 구조상에서 그 답을 찾을 수 있는데, 첫 포스티의 그림을 잠깐 가지고 오겠다.
위의 그림을 보면 모든 요청이 api-gateway를 통해 application단으로 넘어가는 걸 알 수 있는데, 인증이 꼭 user-service에서만 필요하다는 법이 없었다. 즉 엄청 많은 서비스에서 jwt 유효성 체크를 해야할 수 있는 경우가 있을 수 있고 이런 관점에서는 어차피 통과할 api-gateway에서 유효성 체크를 해주는 것이 효율적이다. 다음은 작성한 필터이다.
@Component
@Slf4j
public class AuthorizationHeaderFilter extends AbstractGatewayFilterFactory<AuthorizationHeaderFilter.Config> {
Environment env;
public AuthorizationHeaderFilter(Environment env){
super(Config.class);
this.env = env;
}
public static class Config{
}
@Override
public GatewayFilter apply(Config config) {
return ((exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
if(!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)){
return onError(exchange, "No authorization header", HttpStatus.UNAUTHORIZED);
}
String authorizationHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION).get(0);
System.out.println(authorizationHeader);
String jwt = authorizationHeader.replace("Bearer", "");
if(!isJwtValid(jwt)){
return onError(exchange, "JWT token is not valid", HttpStatus.UNAUTHORIZED);
}
return chain.filter(exchange);
});
}
private boolean isJwtValid(String jwt) {
boolean returnValue = true;
String subject = null;
try{
subject = Jwts.parser().setSigningKey(env.getProperty("token.secret"))
.parseClaimsJws(jwt).getBody()
.getSubject();
}catch (Exception ex){
returnValue = false;
}
if(subject == null || subject.isEmpty())
returnValue = false;
return returnValue;
}
private Mono<Void> onError(ServerWebExchange exchange, String err, HttpStatus httpStatus) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(httpStatus);
log.error(err);
return response.setComplete();
}
}
- config-service
개인적으로 신세계를 경험한 단원이었다. 항상 git에 올릴 때도 application.properties를 빼고 올려서 베포 서버에서 clone할 때 그만한 귀찮음이 없었는데, 이번에 그 문제를 해결할 방법을 알게 되어 기쁘다.
spring은 config server를 지원해준다. 이는 설정 파일을 나누거나 효율적으로 관리할 수 있게 해주는 아주 좋은 기능을 가지고 있다. 아래는 공식 레퍼런스이다.
https://docs.spring.io/spring-cloud-config/docs/current/reference/html/
config server까지 설정을 해주니 다음과 같은 구조가 되었다.
나같은 경우 .yml 설정 파일을 github repository에 올려놓았다. local 파일로도 해보았는데 어후... 에러가 많았고 만약 베포를 한다면 나만의 설정 서버가 따로 있어야 하기에 github를 사용하였다.
3. 결어
지금은 kafka를 활용한 message 처리를 공부하고 있다. 마지막까지 해당 블로그에 글을 올렸으면 좋겠다.
'programming > MSA' 카테고리의 다른 글
[MSA] Config 파일 관리를 위한 Spring cloud bus와 AMQP(Rabbit MQ) (1) | 2023.08.26 |
---|---|
[MSA] Kafka 오류 해결... - Kafka를 완벽하게 삭제하는 방법 (0) | 2023.07.31 |
[MSA] Service Discovery와 API gate-way - Spring cloud netflix Ecreka, Spring cloud gate-way (3) | 2023.07.04 |