월 15,840원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
테스트 코드 작성
항상 강의 잘 듣고 있습니다!postman으로 테스트하다가, 이걸 테스트 코드로 작성해 자동화하면 어떨까? 라고 생각을 해서 테스트 코드를 작성 중입니다.문제는 테스트 코드에서 이벤트 관련 통합 테스트를 어떻게 작성해야 효율적인지 모르겠어요..기존의 테스트 코드로는 이벤트가 한 번씩 늦게 전달되는 경우도 있어서 간헐적으로 실패를 했습니다. 이를 해결하기 위해서 Timeout을 걸어 일정 시간 이내로 이벤트가 도착하는지 체크하고 있는데, 이렇게 되니 전체적인 테스트 속도가 느려지게 되더라고요. 보통 이벤트 관련 테스트는 어떻게 작성을 하나요?
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
gateway와 userService 간의 인증 정보 공유 문제에 관해 질문 드립니다!
안녕하세요 선생님 강의 잘 듣고 있습니다.강의 수강 중 질문이 생겨서요! user-service는 mvc 기반의 app으로 spring security를 통해 인증을 처리하므로, tomcat의 JSESSIONID 를 기반으로 하여 Security Context에 Authentication 객체의 유무를 통해 인증이 된 사용자인지 안 된 사용자인지 Security Filter Chain에서 체크를 하는 것으로 알고 있습니다.그런데gateway에서 설정하신 application.yml 에 따르면 모든 요청 헤더에 존재하는 Cookie를 삭제하고 --> 서버에서 매번 새 요청으로 인식gateway 는 netty 서버를 사용하고 user-service는 tomcat 서버를 사용하잖아요.그래서 두 서버 사이 Context가 공유가 안 될것 같아서요... 그래서 gateway에서는 인증을 했다고 요청을 넘기지만 user-service에서는 그 요청을 받았을 때 해당하는 SESSIONID 의 Context에 Authentication 객체가 존재하지 않아 인증이 필요한 url에 접근할 수 없을 거라고 생각했습니다. 어떻게 인증 완료 정보를 두 서비스가 공유할 수 있는 건가요?? 또한 gateway도 이중화 구성이 가능한가요?.. userService를 2,3중화 한 것처럼 gateway도 여러 대의 인스턴스로 기동하면 eureka에서 다중 구성한 서버로 인식해주는 건가요??... 혹시 gateway에도 Spring Security를 적용시키는 경우도 있을까요?.. 권한 별 접근 제어를 구현하기 위해서는 해당 라이브러리를 사용해야 할 것 같아서요!또한 gateway에서 커스텀 필터를 만들 때, apply 메소드의 return 타입이 GatewayFilter 로 되어있는데, Mono<Void> 타입으로 return을 해도 되는 건가요?... Mono<Void>는 mvc에서 return 타입이 void 인 것과 같은 의미 아닌가요?... 열심히 강의해주셨는데 질문의 너무 많아 죄송합니다..ㅠ 답변 기다리겠습니다! 항상 감사드립니다!!
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
인스턴스 죽은게 대시보드에 표시가 안됩니다.
안녕하세요 수강하면서 질문이 있어 글을 남깁니다.4개의 서비스를 띄우고 작업하는 것을 해보고 있는데 서비스를 중지했음에도 대시보드에는 서버가 계속 남아있습니다.설정이 별로 없는데 적용이 안되는 이유가 혹시 있을까요?
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
서버의 콘솔에 관련된 질문
강의 감사하게 잘 듣고 있습니다.궁금한게 있어서 문의드립니다.프로그램을 셋팅하고 서버를 start하면 이렇게 로그가 출력되면서 왼쪽 빌드창에 계속 뭐가 돌고 있는게 보이는데 이게 서버로 설정해놓아서 그런건가요?
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
pring security관련 질문드려요
저는 msa 구축된 서비스를 인수인계 받아 이해하려고 해당 강의를 듣고있습니다.때문에 지금 강의와 함께 진행중인 공부용 project하나, 운영되고 있는 project하나를 로컬소스로 가지고있는데요.spring secure cofig만 구현해주면 공부용 project에서 구동한 eureka에서 -> 운영project의 microservice가 연동이 됩니다.그리고 eureka서버 콘솔에는 8761로 연결실패했다고 뜹니다(처음에 8761로 공부했다가 7777로 변경) 디펜던씨와 websecurity java를 주석처리하면 정상동작합니다.. 왜그런건가요..도대체.. ? [공부project]Eureka(port:7777)-> gateway(port:8000) -> userservice(port: random)[운영project]gateway(port: 80) -> microservice1(8001)
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
에러 처리 궁금한점
안녕하세요현재는 각 도메인에서 서킷브레이커를 적용했는대,api-gateaway에서는 처리를 해줄 수 없을까요?(공통적으로)현재는 도메인수가 적지만 만약에 라우팅 될 도메인들이 10개 이상 넘어가면 공통적으로 처리할 수 있는 것도 필요해보여서요. (어느 도메인으로 라우팅될조 모르지만)
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
예외처리
안녕하세요. 문득 궁금한 점이 생겼는대요..주문이 성공하고나서 카탈로그 쪽에서 장애가 발생해서 롤백을 해야한다고 했을 때는 처리방안이 어떻게 되나요??찾아보니까 사가패턴 ? 이런거 사용하는것으로 보이는대, 다른 방안도 있을까요? (처리가 좀 어렵네요)
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
spring boot 3.0 이상에서 H2 사용 시 Database not found 문제 해결법 공유
spring boot 3.0이상에서 H2 사용할 때 test connection에서 실패하는 경우가 있을 수 있습니다.에러 메시지로 Database "mem:testdb" not found, either pre-create it or allow remote database creation.이 뜬 경우 아래와 같은 해결책을 사용할 수 있습니다. 우선 에러의 원인은 mem:testdb 데이터베이스가 존재하지 않기 때문에 발생합니다. H2 1.4이상 버전부터는 보안 상 문제 때문에 스프링부트 기동 시 데이터베이스 자동 생성을 막아두었다고 합니다. DB가 없으니 위와 같은 에러 메시지가 발생한 것이죠. H2 dependency 버전을 다운그레이드 시켜도 되겠지만, 솔직히 최신 버전의 dependency를 사용하고 싶잖아요? 문제 해결을 위해서 수동으로 데이터베이스를 생성하면 됩니다. 해결법은 생각보다 간단한데요. 임의의 더미 Entity를 만들어서 DB 생성을 유도하게 만들면 됩니다. 자세한 방법은 해당 블로그의 글을 참고하시기 바랍니다.https://shanepark.tistory.com/435
- 해결됨Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
docker 환경에서 eureka 대시보드 작동
8761:8761 로 포트 바인딩해서 정상 기동했고, docker log 에서도 정상적으로 기동해서 문제없어보이는데, 브라우저로 대시보드 웹페이지 접근하면 "ERR_EMPTY_RESPONSE" 로 나옵니다. 도원님 이미지로 기동해도 똑같은 현상입니다...!
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
Kafka 동기화 문제에 대해 질문이 있습니다.
항상 좋은 강의 감사합니다. 궁금한 점이 있어 질문을 남깁니다. Kafka를 이용해서 멀티 서버에서 하나의 DB를 사용하여 동시성 문제를 해결하는 것을 이해했습니다. 상품 제고가 0이 되면 더 이상 주문을 못하도록 하게 하고 싶습니다. 하지만 Kafka 요청을 통해 비동기로 주문을 하기 때문에 주문을 신청한 순간에는 재고가 있어 주문이 되었지만 Kafka의 모든 처리를 하고 나니 재고가 0이 되어 사실 주문할 수 없는 상황이었습니다. 이런 상황이 발생할 수도 있지 않나요??이럴 때는 어떻게 대처를 해야 하나요??쓰기 작업과 읽기 작업에서 동기화 문제는 어떻게 처리할 수 있나요?
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
ip주소 질문
안녕하세요 강사님!현재 Users Microservice - JPA 부분을 들으면서 user등록까지 잘 해서 테이블에도 잘 나온 상태입니다.저는 client -> api gateway -> 유레카 -> user서비스이렇게 이해하고 있습니다.그리고 현재 집에 같은 와이파이로 연결된 데스크탑으로 (api gateway 역할을 하고 있다고 이해해도 될지 모르겠지만) discovery service를 올려놓았고요.노트북으로 user-service를 만들었습니다.노트북 브라우저로 유레카를 접근하고자 할 때에는 데스크탑 아이피 주소를 입력해서 접근했습니다. 여기까지는 이해가 잘 되었습니다. 그리고 이제 user를 등록하기 위해 postman의 ip주소를 입력하려고 유레카에서 user-service의 포트를 확인하기 위해 클릭하니 노트북 주소와 랜덤 포트가 나오더라고요! 그리고 그 주소로 api를 요청하니 잘 되었습니다. 여기서 질문입니다.모든 서비스는 api gateway를 거치는 것 아닌가요? 그렇다면 api gateway가 동작하고 있는 데스크탑 ip주소를 요청해야하는거 아닌가요? 추가질문으로 환경설정에서 0을 해서 포트가 랜덤으로 설정하게 하시는 이유가 궁금합니다!자세하고 쉽게 설명해주시기 위해 강의 준비해주셔서 감사합니다:)
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
random.value사용 질문있습니다.
안녕하세요 좋은강의 항상 감사합니다! 강의 도중 의문이 생겨서 문의드립니다. 혹시 yml설정에eureka: instance: instance-id: ${spring.cloud.client.hostname}:${spring.application.instance_id:${random.value}}${spring.application.instance_id을 포함하지 않고eureka: instance: instance-id: ${spring.cloud.client.hostname}:${random.value}${random.value}만 포함해도 동일한 값으로 인스턴스가 표시되던데 ${spring.application.instance_id를 포함하신 이유가 궁금합니다. 감사합니다!
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
Kafka Connect Sink 사용할 때 LocalDateTime은 어떻게 하나요??
안녕하세요. 강사님의 강의를 듣고 개인 프로젝트에 적용하고 있습니다.LocalDateTime이 없을 때는 잘 수행되었는데 제 개인 프로젝트 엔티티에는 LocalDateTime이 있습니다. 이 부분에서 자꾸 에러가 나와서 어떻게 처리해야 하는지 알려주시면 감사하겠습니다. 다음은 제가 LocalDateTime을 처리하기 위해 따로 만든 엔티티 입니다.package com.dotd.product.kafkaConnectTest; import jdk.jfr.Name; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; import javax.persistence.*; import java.time.LocalDateTime; @Entity @Data @NoArgsConstructor @AllArgsConstructor @Builder @Table(name = "nametest") @EntityListeners(AuditingEntityListener.class) public class NameTest { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String name; @CreatedDate @Column(name = "created_at") private LocalDateTime createdAt; } 또한, Kafka Connect Sink가 한 번 에러가 발생하면 state : FAILED로 바뀌면서 작동을 안 하는 거 같은데 어떻게 정상화 하나요..?? 127.0.0.1:8083/connectors/nametest-sink-connect/status이 요청을 보냈을 때 이렇게 나옵니다. { "name": "nametest-sink-connect", "connector": { "state": "RUNNING", "worker_id": "192.168.0.14:8083" }, "tasks": [ { "id": 0, "state": "FAILED", "worker_id": "192.168.0.14:8083", "trace": "org.apache.kafka.connect.errors.ConnectException: Exiting WorkerSinkTask due to unrecoverable exception.\r\n\tat org.apache.kafka.connect.runtime.WorkerSinkTask.deliverMessages(WorkerSinkTask.java:611)\r\n\tat org.apache.kafka.connect.runtime.WorkerSinkTask.poll(WorkerSinkTask.java:333)\r\n\tat org.apache.kafka.connect.runtime.WorkerSinkTask.iteration(WorkerSinkTask.java:234)\r\n\tat org.apache.kafka.connect.runtime.WorkerSinkTask.execute(WorkerSinkTask.java:203)\r\n\tat org.apache.kafka.connect.runtime.WorkerTask.doRun(WorkerTask.java:189)\r\n\tat org.apache.kafka.connect.runtime.WorkerTask.run(WorkerTask.java:244)\r\n\tat java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)\r\n\tat java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)\r\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)\r\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)\r\n\tat java.base/java.lang.Thread.run(Thread.java:834)\r\nCaused by: org.apache.kafka.connect.errors.ConnectException: java.sql.SQLException: Exception chain:\r\njava.sql.BatchUpdateException: Column 'created_at' cannot be null\r\n\r\n\tat io.confluent.connect.jdbc.sink.JdbcSinkTask.put(JdbcSinkTask.java:124)\r\n\tat org.apache.kafka.connect.runtime.WorkerSinkTask.deliverMessages(WorkerSinkTask.java:581)\r\n\t... 10 more\r\nCaused by: java.sql.SQLException: Exception chain:\r\njava.sql.BatchUpdateException: Column 'created_at' cannot be null\r\n\r\n\tat io.confluent.connect.jdbc.sink.JdbcSinkTask.getAllMessagesException(JdbcSinkTask.java:154)\r\n\tat io.confluent.connect.jdbc.sink.JdbcSinkTask.put(JdbcSinkTask.java:104)\r\n\t... 11 more\r\n" } ], "type": "sink" }
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
SpringBoot 3점대 버전 Spring Security 설정
Spring Security 가 3점대 버전으로 오면서 상당한 변화가 있습니다. 강의 내용을 따라 하다보니 순환참조나, 현재는 지원하지 않는 기능이 상당수 존재하였습니다. 현재 작업한 코드가 문제 해결에 많은 도움이 되면 좋겠어서 글을 첨부합니다. SecurityConfig.class 입니다.@Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig{ private final CustomAuthenticationManager customAuthenticationManager; private final UserFindPort userFindPort; private final Environment environment; @Bean public WebSecurityCustomizer webSecurityCustomizer() { return (web) -> web.ignoring(). requestMatchers(new AntPathRequestMatcher("/h2-console/**")) .requestMatchers(new AntPathRequestMatcher( "/favicon.ico")) .requestMatchers(new AntPathRequestMatcher( "/css/**")) .requestMatchers(new AntPathRequestMatcher( "/js/**")) .requestMatchers(new AntPathRequestMatcher( "/img/**")) .requestMatchers(new AntPathRequestMatcher( "/lib/**")); } @Bean protected SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { http.csrf(AbstractHttpConfigurer::disable); http.authorizeHttpRequests(authorize -> authorize.requestMatchers(new MvcRequestMatcher(introspector, "/**")).permitAll() // requestMatchers(new MvcRequestMatcher.Builder(introspector).pattern(HttpMethod.GET, "/users/**")).permitAll() // .requestMatchers(new MvcRequestMatcher(introspector, "/greeting")).permitAll() // .requestMatchers(new MvcRequestMatcher(introspector, "/welcome")).permitAll() // .requestMatchers(new MvcRequestMatcher(introspector, "/health-check")).permitAll() // .requestMatchers(new MvcRequestMatcher.Builder(introspector).pattern(HttpMethod.POST, "/users")).permitAll() .anyRequest() .authenticated()) .addFilter(getAuthenticationFilter()) .httpBasic(Customizer.withDefaults()); return http.build(); } private AuthenticationFilter getAuthenticationFilter() { return new AuthenticationFilter(customAuthenticationManager, userFindPort, environment); } }requestMatcher에서 AntPathRequestMatcher, MvcRequestMatcher에 관한 설명은부족하지만 https://velog.io/@dktlsk6/Spring-Security-RequestMatcher에서 확인 가능하십니다. CustomUserDetailService.class 입니다. 순환참조 문제가 발생하여 강의와 달리 새로 CustomService를 생성하여 implements 하였습니다.@Component @RequiredArgsConstructor public class CustomUserDetailService implements UserDetailsService { private final UserFindPort userFindPort; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserDto userByEmail = userFindPort.findUserByEmail(username); if (userByEmail == null) { throw new UsernameNotFoundException("User Not Found"); } return new User(userByEmail.getEmail(), userByEmail.getEncPasswd(), true, true, true, true, new ArrayList<>()); } } CustomAuthenticationManager.class 입니다. AuthenticationFilter의 AuthenticationManager로 사용할 것입니다.@Component @RequiredArgsConstructor @Slf4j public class CustomAuthenticationManager implements AuthenticationManager { private final CustomUserDetailService customUserDetailService; @Bean protected PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { UserDetails userDetails = customUserDetailService.loadUserByUsername(authentication.getName()); if (!passwordEncoder().matches(authentication.getCredentials().toString(), userDetails.getPassword())) { throw new BadCredentialsException("Wrong password"); } return new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities()); } } AuthenticationFilter.class 입니다. 해당 부분은 강의와 차이점이 없습니다.@Slf4j public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter { private final UserFindPort userFindPort; private final Environment environment; public AuthenticationFilter(AuthenticationManager authenticationManager, UserFindPort userFindPort, Environment environment) { super.setAuthenticationManager(authenticationManager); this.userFindPort = userFindPort; this.environment = environment; } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { try { LoginRequestDto creds = new ObjectMapper().readValue(request.getInputStream(), LoginRequestDto.class); UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(creds.getEmail(), creds.getPassword(), new ArrayList<>()); return getAuthenticationManager().authenticate(token); } catch (IOException e) { throw new RuntimeException(e); } } @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { String username = authResult.getName(); UserDto user = userFindPort.findUserByEmail(username); if (user == null) { throw new UsernameNotFoundException(username); } log.debug("user id {}", user.getUserId()); String token = Jwts.builder() .setSubject(user.getUserId()) .setExpiration(new Date(System.currentTimeMillis() + Long.parseLong(environment.getProperty("token.expiration.time")))) .signWith(SignatureAlgorithm.HS512, environment.getProperty("token.secret")) .compact(); response.addHeader("token", token); response.addHeader("userId", user.getUserId()); } } 아래는 실제 결과입니다.404가 뜨는 이유는 login 성공시 redirect url을 설정해주지 않아서 /(루트) 경로로 이동해서입니다. 해당 경로와 매핑되는 resource나 api가 없기 때문에 해당 오류가 발생한것이므로 정상작동으로 생각하시면 됩니다.아래는 잘못된 정보를 기입하여 실패 테스트 입니다. 추후 강의를 들으며 업데이트 하도록 하겠습니다.
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
3강 Spring Cloud Gateway - Custom Filter 적용 Bean 관련 질문있습니다.
안녕하세요 수업 잘 듣고 있습니다. 수업중 내용에 관해서 질문이 있어서 질문을 남깁니다. 수업 5분50초쯤에 Gateway Filter를 Bean으로 하나 등록한다고 하셨는데 @Component어노테이션이 붙은 클래스의 아래의 메소드의 반환값은 자동으로 Bean으로 등록되나요? @Bean어노테이션을 붙여줘야 등록이되는 줄 알았는데 제가 잘못이해하고있었는지 궁금해서 질문을 남깁니다.
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
hasIpAddress(), getRemoteAddr() 질문입니다.
이전에 이런 질문들((https://www.inflearn.com/questions/423204))이 있던 것을 확인하였으나 저는 해결이 되지 않아 질문을 남깁니다.postman으로 회원가입하고 로그인하려고 하면 401 Unauthorized가 나며 많이 보셨을 이런 에러가 나옵니다.java.lang.UnsupportedOperationException: public abstract java.lang.String javax.servlet.ServletRequest.getRemoteAddr() is not supported....이와 같은 에러의 질문과 답변을 보고 hasIpAddress()에서 .access("hasIpAddress('" + IP + "')")로 바꿔서 해보았는데도 또는 스프링 부트 버전을 바꾸어 시도해(2.6.2, 2.4.2 등)보았으나 해결이 되지 않아 질문을 드립니다.처음 설정한 spring boot 버전은 2.7.15입니다.build.gradleplugins { id 'java' id 'org.springframework.boot' version '2.7.15' id 'io.spring.dependency-management' version '1.0.15.RELEASE' } group = 'com.example' version = '0.0.1-SNAPSHOT' java { sourceCompatibility = '11' } configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } ext { set('springCloudVersion', "2021.0.8") } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'com.h2database:h2:1.3.176' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.modelmapper:modelmapper:3.1.1' implementation 'org.springframework.boot:spring-boot-starter-security' testImplementation 'org.springframework.security:spring-security-test' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' } dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" } } tasks.named('test') { useJUnitPlatform() } WebSecurity은@Configuration @EnableWebSecurity public class WebSecurity extends WebSecurityConfigurerAdapter { private final Environment environment; private final UserService userService; private final BCryptPasswordEncoder bCryptPasswordEncoder; private String IP = "192.168.1.2"; @Autowired public WebSecurity(Environment environment, UserService userService, BCryptPasswordEncoder bCryptPasswordEncoder) { this.environment = environment; this.userService = userService; this.bCryptPasswordEncoder = bCryptPasswordEncoder; } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); http.authorizeRequests() .antMatchers("/**") // .hasIpAddress(IP) .access("hasIpAddress('" + IP + "')") .and() .addFilter(getAuthenticationFilter()); http.headers().frameOptions().disable(); } private AuthenticationFilter getAuthenticationFilter() throws Exception { AuthenticationFilter authenticationFilter = new AuthenticationFilter(authenticationManager(), userService, environment); return authenticationFilter; } // db password와 input password 비교 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userService).passwordEncoder(bCryptPasswordEncoder); } }2.7 이후 버전에서는 https://www.inflearn.com/chats/789887와 같이 WebSecurityConfigurerAdapter 를 상속하지 않고 configure함수 오버라이드 대신 SecurityFilterChain을 사용해보았으나 이렇게 해도 되지 않았습니다.AuthenticationFilter에 unsuccessfulAuthentication를 오버라이드하여 확인해본 결과org.springframework.security.authentication.BadCredentialsException: 자격 증명에 실패하였습니다. at org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticationChecks(DaoAuthenticationProvider.java:80) at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:147) at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182) at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:201) at com.example.userservice.filter.AuthenticationFilter.attemptAuthentication(AuthenticationFilter.java:46)라고 오류가 나오는 것을 확인했습니다.AuthenticationFilter.java:46 부분은 return getAuthenticationManager().authenticate( 부분 입니다.AuthenticationFilter 코드는 다음과 같습니다.@Slf4j public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter { private final UserService userService; private final Environment environment; public AuthenticationFilter(AuthenticationManager authenticationManager, UserService userService, Environment environment) { super.setAuthenticationManager(authenticationManager); this.userService = userService; this.environment = environment; } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { try { RequestLogin creds = new ObjectMapper().readValue(request.getInputStream(), RequestLogin.class); return getAuthenticationManager().authenticate( new UsernamePasswordAuthenticationToken( creds.getEmail(), creds.getPassword(), new ArrayList<>() ) ); } catch (IOException e) { throw new RuntimeException(e); } } @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { // log.debug(((User)authResult.getPrincipal()).getUsername()); String userName = ((User)authResult.getPrincipal()).getUsername(); UserDto userDetails = userService.getUserDetailsByEmail(userName); System.out.println("details :" + userDetails); String token = Jwts.builder() .setSubject(userDetails.getUserId()) .setExpiration( new Date((System.currentTimeMillis() + Long.parseLong(environment.getProperty("token.expiration_time")))) ) .signWith(SignatureAlgorithm.HS512, environment.getProperty("token.secret")) .compact(); System.out.println("token :" + token); response.addHeader("token", token); response.addHeader("userId", userDetails.getUserId()); } @Override protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException { // super.unsuccessfulAuthentication(request, response, failed); failed.printStackTrace(); } } 어느 부분을 어떻게 수정하여 진행을 해야 할까요? AuthenticationFilter에서 attemptAuthentication 함수를 UsernamePasswordAuthenticationToken 받는 것으로 수정하여 디버깅해보니 아래 코드의 authenticationToken 값은 잘 나옵니다. 그런데 위의 질문처럼 getAuthenticationManager().authenticate 여기서 문제가 발생합니다.문제가 발생하는 부분은 AbstractAuthenticationProcessingFilter의 저 부분으로 잡히며AuthenticationFilter 코드는 다음과 같습니다.import com.example.userservice.dto.UserDto; import com.example.userservice.service.UserService; import com.example.userservice.vo.RequestLogin; import com.fasterxml.jackson.databind.ObjectMapper; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import lombok.extern.slf4j.Slf4j; import org.springframework.core.env.Environment; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.User; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.Date; @Slf4j public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter { private final UserService userService; private final Environment environment; public AuthenticationFilter(AuthenticationManager authenticationManager, UserService userService, Environment environment) { super.setAuthenticationManager(authenticationManager); this.userService = userService; this.environment = environment; } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { try { RequestLogin creds = new ObjectMapper().readValue(request.getInputStream(), RequestLogin.class); UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( creds.getEmail(), creds.getPassword(), new ArrayList<>()); return getAuthenticationManager().authenticate(authenticationToken); } catch (IOException e) { throw new RuntimeException(e); } } @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { // log.debug(((User)authResult.getPrincipal()).getUsername()); String userName = ((User)authResult.getPrincipal()).getUsername(); UserDto userDetails = userService.getUserDetailsByEmail(userName); System.out.println("details :" + userDetails); String token = Jwts.builder() .setSubject(userDetails.getUserId()) .setExpiration( new Date((System.currentTimeMillis() + Long.parseLong(environment.getProperty("token.expiration_time")))) ) .signWith(SignatureAlgorithm.HS512, environment.getProperty("token.secret")) .compact(); System.out.println("token :" + token); response.addHeader("token", token); response.addHeader("userId", userDetails.getUserId()); } // @Override // protected void unsuccessfulAuthentication(HttpServletRequest request, // HttpServletResponse response, // AuthenticationException failed) throws IOException, ServletException { //// super.unsuccessfulAuthentication(request, response, failed); // failed.printStackTrace(); // } } 해결 방법 좀 알려주시면 감사하겠습니다.
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
강의자료
강의자료는 따로 없을까요?
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
섹션 16 mysql 문의드립니다
$ docker run -d -p 3306:3306 --network ecommerce-network --name mariadb nhw0926/my-mariadb:1.0c5aed5c624e8c48d18a32f8beea882f5373745350a4a069f64058d459045016ddocker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "mysqld": executable file not found in $PATH: unknown 실행 시 위와같은 오류가 발생하는데 몇시간을 찾아도 도저히 답이나오지않습니다.....하...아시는분있을까요
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
Spring boot 3.1.3, Security 6.1.3 버전 업데이트
학습이 너무 예전거라 최신 스프링과 security 버전이 달라서 많이 바뀐것 같습니다. 강의 최신화좀 빨리 해주세요 진도가 안나갑니다 해결하느라
- 미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
섹션14 Prometheus와 Grafana 설치 강의 내용중 문의 드립니다
강의 내용대로 진행하였는데http://localhost:8000/user-service/actuator/prometheushttp://localhost:8000/order-service/actuator/prometheus둘다 아래 이미지와같은 에러가 발생합니다 apigateway application.yml 설정- id: user-service uri: lb://USER-SERVICE predicates: - Path=/user-service/actuator/** - Method=GET,POST filters: - RemoveRequestHeader=Cookie - RewritePath=/user-service/(?<segment>.*), /$\{segment} - id: order-service uri: lb://ORDER-SERVICE predicates: - Path=/order-service/actuator/** - Method=GET filters: - RemoveRequestHeader=Cookie - RewritePath=/order-service/(?<segment>.*), /$\{segment} 프로메테우스.yml 설정static_configs: - targets: ["localhost:9090"] - job_name: 'user-service' scrape_interval: 15s metrics_path: '/user-service/actuator/prometheus' static_configs: - targets: ['localhost:8000'] - job_name: 'order-service' scrape_interval: 15s metrics_path: '/order-service/actuator/prometheus' static_configs: - targets: ['localhost:8000'] - job_name: 'apigateway-service' scrape_interval: 15s metrics_path: '/actuator/prometheus' static_configs: - targets: ['localhost:8000'] apigateway 의 AuthorizationHeaderFilter.java// 절차 // login -> token반환받음 -> client에서 apigateway로 정보 요청 시 (토큰정보를 가지고 요청함) -> 서버에서는 토큰정보 검증 (header 안에 토큰이 포함됨) 38줄 @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); // 반환값은 list배열이기에 0 String jwt = authorizationHeader.replace("Bearer", ""); if(!isJwtValid(jwt)) { return onError(exchange, "JWT token is not valid", HttpStatus.UNAUTHORIZED); } return chain.filter(exchange); }); }여기서 지속적으로 아래 오류가 발생중입니다2023-09-10 01:15:35.241 INFO 31372 --- [tor-http-nio-10] c.e.a.filter.GlobalFilter : Global Filter baseMessage: Spring Cloud Gateway Global Filter2023-09-10 01:15:35.241 INFO 31372 --- [tor-http-nio-10] c.e.a.filter.GlobalFilter : Global Filter Start: request id -> a5f590c1-10982023-09-10 01:15:35.270 INFO 31372 --- [tor-http-nio-10] c.e.a.filter.GlobalFilter : Global Filter End: response code -> 404 NOT_FOUND2023-09-10 01:15:35.528 INFO 31372 --- [tor-http-nio-12] c.e.a.filter.GlobalFilter : Global Filter baseMessage: Spring Cloud Gateway Global Filter2023-09-10 01:15:35.528 INFO 31372 --- [tor-http-nio-12] c.e.a.filter.GlobalFilter : Global Filter Start: request id -> d5aec101-10992023-09-10 01:15:35.528 ERROR 31372 --- [tor-http-nio-12] c.e.a.filter.AuthorizationHeaderFilter : no authorization header2023-09-10 01:15:35.528 INFO 31372 --- [tor-http-nio-12] c.e.a.filter.GlobalFilter : Global Filter End: response code -> 401 UNAUTHORIZED 이 필터관련 수정한건 없는것으로 기억하는데 제가 놓친게있을까요답답하네요 ㅠ