개요
- 모노리스 서비스에서 적용된 jwt 인증을 마이크로 서비스에서 jwt 인증을 할 수 있도록 구현하기
- user와 관련된 내용이지만 게시글 작성, 댓글 작성 등 인가가 필요한 활동을 할 때마다 user-service를 거치지 않을 것
- 인증/인가가 필요하지 않은 서비스와 필요한 서비스를 구별
접근방법
- 모든 요청을 가장 먼저 받아서 처리하는 api-gateway에서 인증/인가를 구현
- AbstractGatewayFilterFactory<>를 상속받는 filter를 사용
- 인증/인가가 필요한 서비스와 필요하지 않는 서비스를 나누어서 두 개의 filter를 각각 적용
해결과정
- 인증/인가가 필요하지 않는 서비스에는 NoTokenRequiredFilter를 적용 (회원가입, 로그인, 이메일 인증, feign-client 등)
- 인증/인가가 필요한 서비스에는 AuthFilter를 적용 (프로필 변경, 게시글 작성, 댓글 작성 등)
- AuthFilter에서는 전달받은 토큰을 검증하고, 필요한 정보(userId)를 추출하여 Header에 담아서 전달
- 해당 서비스는 Header에 담긴 userId를 꺼내서 로직을 구현한다.
토큰 추출 및 전달 코드
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
if (request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
// header에 담긴 accessToken 추출 및 검증
String accessToken = request.getHeaders().get(HttpHeaders.AUTHORIZATION).get(0).substring(7);
validBlackToken(accessToken);
if (tokenProvider.validateToken(accessToken)) {
Long userId = tokenProvider.getUserId(accessToken);
log.info("유저의 아이디는 -> {}", userId);
// header에 userId를 담아서 전달
request.mutate().header("Auth", "true").build();
request.mutate().header("userId", String.valueOf(userId)).build();
tokenProvider.setHeaderAccessToken(response, accessToken);
return chain.filter(exchange);
} else if(!tokenProvider.validateToken(accessToken)) {
boolean isExist = tokenProvider.isExistRefreshToken(accessToken);
if (isExist) {
// RefreshToken으로 AccessToken 재발급 및
// header에 userId 담아서 전달
return chain.filter(exchange);
}
}
}
return onError(exchange, "권한없음 : 토큰이 필요합니다.", HttpStatus.UNAUTHORIZED);
인증/인가가 필요없는 filter
public GatewayFilter apply(Config config) {
// 아무런 작업을 하지 않는다.
return (exchange, chain) -> {
return chain.filter(exchange);
};
}
결론
- 인증/인가가 필요하지 않은 회원가입, 로그인, 이메일인증을 세 번 작성하지 않고 한 번에 작성하도록 url 수정
'멋진 개발자 > 트러블슈팅' 카테고리의 다른 글
트러블 슈팅 - 준비된 재고는 200개인데 240명이 구매를 성공한 건에 대하여 (0) | 2024.03.15 |
---|---|
트러블 슈팅 - RefreshToken을 활용한 보안성 높이기 (0) | 2024.03.03 |
트러블 슈팅 - JavaMailSender 객체로 이메일 인증하기 (0) | 2024.03.03 |