문제 사항은 다음과 같았다.
나는 Springboot와 Flutter를 연결하는 작업을 하고 있었고, Springboot Security를 사용하여 authenticated 옵션을 걸어놨었다.
이렇게 authenticated가 걸려있는 주소로 flutter에서 get을 요청할 때 authorization을 넣어서 보내줘야하는데 자꾸만 제대로 된 값을 읽어오지 못하는 것이었다.
Uri getUri = Uri.parse("http://localhost:8080/api/parking/data");
final response = await http.get(getUri, headers: {
HttpHeaders.authorizationHeader: _userProvider.token,
'content-type': 'application/json'
});
if (response.statusCode != 200) {
return false;
}
Securing OPTIONS /api/parking/data
...
Failed to authorize filter invocation [OPTIONS /api/parking/data] with attributes [authenticated]
Access-Control-Request-Method: GET
Access-Control-Request-Headers: authorization, content-type
원인은 springboot security에서 설정했던 authenticated attributes 를 가진 OPTIONS /api/parking/data가 filter invocation을 authorize하는 데에 실패했다는 말이다.
처음엔 이게 뭔 말인지조차 이해할 수 없었다. 난 GET으로 보냈는데 OPTIONS는 뭔데..? Authorization이 왜 헤더에 있지 않고 Access-Control-Request-Headers 안으로 들어간 거지? 난 authorization을 헤더로 넣어줬는데?
그래서 열심히 구글링 해본 결과, 우선 Access-Control-Request-Headers 요청 헤더는 브라우저에서 prefligt 요청을 실행할 때 '서버에 실제 요청이 있을 때 클라이언트가 보낼 수 있는 http 헤더'를 알려주는 데에 사용된다고 한다. preflight 요청은 cors 요청 시에 특정 조건이 맞지 않는 경우에 먼저 OPTIONS 방식으로 보낸 이후에 다시 정상 request를 날린다고 한다. 즉, 나의 문제는 cors 요청에서 어떤 조건에 걸려서 preflight로 먼저 요청이 가는데 이 요청이 막힌 것이 문제였다.
그 전에 간단하게 CORS를 짚고 넘어가보자.
CORS는 Cross-Origin Resource Sharing의 약어로 다른 출처의 자원을 공유하는 것이다.
웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 Cross-Origin HTTP 요청을 실행한다.
이 CORS HTTP(s) 요청에는 두가지 요청 방식이 있다. 조건과 함께 살펴보자.
첫번째, Simple Request(단순 요청)이다.
두번째, Preflight Request(프리플라이트 요청)이다.
따라서 나의 경우에서는 Content-type을 application/json을 썼고, authorization 헤더 즉, 사용자 정의 헤더가 설정되었기 때문에 요청이 preflighted 처리가 된 것이다.
"preflighted" request는 위에서 논의한 “simple requests” 와는 달리, 먼저 OPTIONS 메서드를 통해 다른 도메인의 리소스로 HTTP 요청을 보내 실제 요청이 전송하기에 안전한지 확인한다. cross-origin 요청은 유저 데이터에 영향을 줄 수 있기 때문에 이와같이 미리 전송(preflighted)합니다.
따라서 나의 해결방법은 Springboot에서 preflight로 들어오는 요청들을 permitAll 할 수 있도록 바꾸었다.
.antMatchers(HttpMethod.OPTIONS, "/**/*").permitAll()
위와 같이 코드를 security에 추가해주고 성공하면 다음과 같이 화면이 뜬다.
본 요청에 들어간 Authorization 헤더를 보여주고 결과 값으로 토큰을 성공적으로 불러온다.
참고자료