1. 목적
- msa 프로젝트를 하면서 api에 대한 인가처리가 필요했다.
- 인가처리를 위해서 구상한 아키텍쳐는 kong g/w를 사용하여 lua로 plugin을 작성했다. (plugin to 인가모듈)
- 진행 과정에서 인가처리를 위한 Kong 사용과 lua를 사용하는 것에 대한 불편함이 느껴졌다. 나혼자 하면 괜찮겠지만 팀원들에게 민폐다.
- 그러다가 재미난 글을 보게되었다. 사이드카 프록시로 구현한 서비스 인증
- 그대로 구현해본다.
2. 글을 통해 알 수 있는 점
- webflux로 구현하셨다. mvc도 가능한데, @RequestMapping 사용에 약간의 문제가 있다. (메소드 별로 구현해야했음)
- 끝..
3. 구현
- proxy의 본체는 그대로 구현한다. 요청 정보를 target 서비스로 그대로 넘겨준다.
@RequestMapping(value = "/**")
public Mono<ResponseEntity<byte[]>> proxy(ServerHttpRequest request, ProxyExchange<byte[]> proxy) {
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpRequest(request);
String modifiedUri = builder.scheme(targetScheme).host(targetHost).port(targetPort).build(false)
.toUriString();
return proxy.uri(modifiedUri).forward(r -> {
HttpHeaders filtered = filter(r.getHeaders());
return ResponseEntity.status(r.getStatusCode()).headers(filtered).body(r.getBody());
});
}
- spring security 생각보다 여기서 고생을 좀 많이..했다. (boot 3.1 환경에서 작동합니다. webflux + boot3를 처음 시도한 사람)
@Configuration
@RequiredArgsConstructor
@EnableWebFluxSecurity
@Slf4j
public class SecurityConfig {
private final CustomAuthenticationConverter customAuthenticationConverter;
private final CustomAuthorizationManager customAuthorizationManager;
private static final String[] AUTH_WHITELIST = {
"/*/swagger-ui/**",
"/*/v3/api-docs/**",
....
};
@Bean
public SecurityWebFilterChain filterChain(ServerHttpSecurity http) throws Exception {
ReactiveAuthenticationManager authenticationManager = Mono::just;
AuthenticationWebFilter authenticFilter = new AuthenticationWebFilter(authenticationManager);
authenticFilter.setServerAuthenticationConverter(customAuthenticationConverter);
http
.csrf(csrf -> csrf.disable())
.headers(c -> c.frameOptions(f -> f.disable()).disable())
.httpBasic(h -> h.disable())
.securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
.authorizeExchange(exchanges -> {
exchanges.pathMatchers(AUTH_WHITELIST).permitAll();
exchanges.pathMatchers("/**").access(customAuthorizationManager);
}
)
.addFilterAt(authenticFilter, SecurityWebFiltersOrder.AUTHENTICATION)
.exceptionHandling(r-> {
r.accessDeniedHandler(new CustomAccessDeniedHandler());
r.authenticationEntryPoint(new CustomAuthenticationEntryPoint());
})
;
return http.build();
}
}
- 인가처리 CustomAuthorizationManager
- ReactiveAuthorizationManager의 check method를 Override
- 해당 method에서 권한이 일치하면 AuthorizationDecision 를 true로 아닐 경우 false로 처리
- 필요한 인가 처리에 맞게 비즈니스 로직을 작성
- 어플리케이션 main이 작동하면 바로 인가데이터를 캐시로 저장해서 올려두고 request 정보와 대조하여 처리