-
카테고리
-
세부 분야
백엔드
-
해결 여부
미해결
갑자기 127.0.0.1:8000/user-service/** 가 작동하지 않습니다..
22.08.29 17:02 작성 조회수 397
1
안녕하세요 현재 Microservice간 통신의
RestTemplate 사용 강의를 듣던중에 포스트맨으로 테스트를 하는데
POST 방식 요청인
127.0.0.1:8000/user-service/users
127.0.0.1:8000/user-service/login 은 잘됩니다.
<br>
하지만 GET 방식 요청인
127.0.0.1:8000/user-service/users
127.0.0.1:8000/user-service/users/welcome
127.0.0.1:8000/user-service/users/health_check
127.0.0.1:8000/user-service/users/{userId} 가 먹히지 않습니다.
즉 디버깅 브레이크 포인트도 안걸리고 그냥 401 에러가 발생합니다...
즉,
127.0.0.1:8000/user-service/login 으로 얻은 response의 Header에 있는 token을가지고
요청할 때 Bearer Token에 넣어도 401 에러가 발생합니다...
난감합니다...
갑자기 잘 되다가 왜이런지 모르겠네요..
분명 apigateway-service의 application.yml에
get방식은 AuthorizationHeaderFilter 를 걸어줬습니다..
- id: user-service
uri: lb://USER-SERVICE
predicates: # 조건절이다.
- Path=/user-service/**
- Method=GET
filters:
- RemoveRequestHeader=Cookie
- RewritePath=/user-service/(?<segment>.*), /$\{segment}
- AuthorizationHeaderFilter
<br>
그런데 정말 이해가 안가는것이
get 방식으로
127.0.0.1:8000/user-service/** 요청을 하면 Bearer Token을 정상적으로 넣어도 401 에러가 발생하는데
get 방식으로 user-service의 자체 포트번호를 넣고
127.0.0.1:67026/** 이런식으로 요청하면 BearerToken을 잘못 넣어도 정상적으로 작동합니다...
대체 왜이런거죠??
<br>
참고로 현재 저는 대칭키 방식을 이용한 암호화를 사용하고 있습니다.(비대칭키 암호화는 적용하지 않았습니다.)
그런데 이것은 user-service에서 get방식으로 요청하는데 문제가 있어보이지는 않습니다..
어떻게 하면 get방식에서 401 에러를 발생하지 않도록 할 수 있을까요?
아니면 더 확인해야할 정보가 뭐가 있을까요?
감사합니다.
<br>
현재
apigateway-service의 application.yml이 아래와 같이 되있고
spring:
cloud:
config:
uri: http://127.0.0.1:8888
name: ecommerce # ecommerce.yml 파일을 가져온다.
native에 있는 ecommerce.yml 은 다음과 같습니다.
token:
expiration_time: 86400000
secret: user_token_native_ecommerce
gateway:
ip: 192.168.45.163
참고로 token.secret이 user_token_native_ecommerce는 해당 ecommerce.yml 파일 밖에 없기 때문에 경로는 확실합니다. ( 확실히 config-service 의 application의 search-locations 경로 안에 ecommerce.yml 파일이 있습니다.)
대체 뭐가 문제여서 get 방식으로
127.0.0.1:8000/user-service/** 요청이 401 에러가 발생하는 것일까요?
<br>
혹시나해서 UserController도 같이 올려봅니다.
@RestController
@RequestMapping("/")
public class UserController {
private Environment env;
private UserService userService;
@Autowired
private Greeting greeting;
@Autowired
public UserController(Environment env, UserService userService) {
this.env = env;
this.userService = userService;
}
@GetMapping("/health_check")
public String status() {
return String.format("It's Working in User Service"
+ ", port(local.server.port)="+ env.getProperty("local.server.port")
+ ", port(server.port)="+ env.getProperty("server.port")
+ ", token secret="+ env.getProperty("token.secret")
+ ", token expiration time="+ env.getProperty("token.expiration_time"));
}
@GetMapping("/welcome")
public String welcome() {
//return env.getProperty("greeting.message");
return greeting.getMessage();
}
@PostMapping("/users") // 제네릭타입으로 반환할 형태도 명시할 수 있다.
public ResponseEntity<ResponseUser> createUser(@RequestBody RequestUser user) {
ModelMapper mapper = new ModelMapper();
mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
// RequestUser를 UserDto로 매핑한다.
UserDto userDto = mapper.map(user, UserDto.class);
userService.createUser(userDto);
// userDto 를 ResponseUser 형으로 변경한다.
ResponseUser responseUser = mapper.map(userDto, ResponseUser.class);
// rest api 식으로 반환하자
return ResponseEntity.status(HttpStatus.CREATED).body(responseUser); // 201번 성공코드 반환
}
@GetMapping("/users")
public ResponseEntity<List<ResponseUser>> getUsers() {
Iterable<UserEntity> userList = userService.getUserByAll();
List<ResponseUser> result = new ArrayList<>();
userList.forEach(v -> {
result.add(new ModelMapper().map(v, ResponseUser.class));
}); // v를 ResponseUser 클래스로 변경
return ResponseEntity.status(HttpStatus.OK).body(result);
}
@GetMapping("/users/{userId}")
public ResponseEntity<ResponseUser> getUser(@PathVariable("userId") String userId) {
UserDto userDto = userService.getUserByUserId(userId);
ResponseUser returnValue = new ModelMapper().map(userDto, ResponseUser.class);
return ResponseEntity.status(HttpStatus.OK).body(returnValue);
}
}
답변을 작성해보세요.
0
Dowon Lee
지식공유자2022.08.30
안녕하세요, 이도원입니다.
발생하신 문제에 대해 잘 정리해서 올려 주셨네요. 원인을 정확하게는 알기 어렵지만, user-service에 직접 요청하는 작업은 실행되나, apigateway-service를 거쳐 실행하는 서비스는 401 오류가 발생한다는 것 같습니다. Token 자체의 문제라기 보다는 user-service에서 apygateway-service로 부터 전달되는 요청 처리가 안되는 거 같습니다. 현 상황으로 확인해 보실 수 있는 부분은, user-service의 WebSecurity에서 apigateway-service의 IP를 확인해 보시면 좋을 것 같습니다. WebSecurity 작업 시 아래 처럼, 요청 URI Pattern 및 IP를 제약하는 부분이 있어서, 여기에서 문제가 생길 것 일수도 있을 것 같습니다.
추가로, BearerToken을 잘못 넣어도 정상적으로 작동 되었다는 부분은, 잘못 된 Token을 사용하였다는 의미인가요? 아니면, 현재 발급 된 Token이 아닌, 이전 Token을 사용하셨다는 건가요? 만약 이전 Token을 사용하는 문제였다면, Token 자체가 지급 발급된 것인지에 대해서는 검증하지 않고, 유효한지만 검증하고 있기 때문에, 새로운 Token을 사용하지 않아도 정상 처리가 될 수 있습니다.
작업하시는데 계속 문제가 발생하면, user-service, apigateway-service 코드를 압축하여 아래 이메일로 보내주시면, 제 환경에서도 테스트 해 보도록 하겠습니다.
감사합니다.
리자몽
질문자2022.08.30
천절한 답변 감사합니다.
제가 메일을 보냈는데 조금 성급하게 보냈습니다..
디버깅하데 에러를 검색하는데 문제를 해결했습니다.
디버깅 하다가 user-service의 get방식 요청으로 토큰 검사하는데
io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
에러가 나왔습니다. 에러를 검색해보니까
각 마이크로 서비스의 secret_token 값을 같게 해줘야 되는데 다르게 설정되어 있어서 문제가 발생했습니다.
현재 apigateway-service는 ecommerce.yml 을 가져오게 설정이 돼있었고
spring:
cloud:
config:
uri: http://127.0.0.1:8888
name: ecommerce # ecommerce.yml 파일을 가져온다.
user-service는 user-service.yml을 가져오도록 설정이 돼있었습니다.
spring:
cloud:
config:
uri: http://127.0.0.1:8888
name: user-service # user-service.yml 파일을 가져온다.
하지만 user-service.yml파일과
ecommerce.yml 파일의 token.secret 값이 달랐습니다..
token:
expiration_time: 86400000
secret: user_token_native_user_service
이 token.secret 값을 같게하니까
기존에 apigateway-service를 사용해서 user-service를 get방식으로 요청하는건 이상없이 잘 되고 있습니다.
결론은 마이크로서비스(user-service)가 apigateway를 거쳐가려면
마이크로서비스와 apigateway의 token의 secret 값을 같게 해줘야 되는군요
답변 1