swagger에서 인증 설정으로 인한 QHttpServer 핸들러 처리

이상문
7 min readNov 14, 2022

--

Preflight request 에 관하여

이해한 바로는 실제 리소스를 요청하기 전에 OPTIONS 요청을 날려서 CORS 정책 여부를 클라이언트에서 파악하는 방식 정도로 정리할 수 있겠다.

문제에 관해서

swagger editor를 통해서 QHttpServer 에서 작성한 API를 test 하려는데 문제가 발생하고 말았다. swagger editor에서 특정 경로에 대해서 basic auth 설정을 했지만, QHttpServer에서는 요청을 받지 못했다. 바로 preflight request 때문이었다. swagger에서 apiKey라는 요청에 대해서 basic auth 을 다음과 같이 설정했다.

 /apiKey:
post:
security:
- basicAuth: []
tags:
- apiKey
summary: Access key 획득
description: Access key를 얻는다.
...

basic auth 에 대한 설정은 다음 swagger 가이드에서 확인할 수 있다.

components 설정에 securitySchemes 항목으로 넣어주면 된다.

components:
securitySchemes:
basicAuth: # <-- arbitrary name for the security scheme
type: http
scheme: basic

설정을 하고, 개발 중인 웹 서버에 apiKey 경로에 대한 서비스를 작성 후, swagger UI 페이지를 통해 요청을 했지만, 묵묵부답이었다.

별로 도움은 안 되지만 에러메시지를 발생시키면서, Code 자체도 받지 못한 결과를 보여 준다.

해결의 실마리

삽질 끝에, swagger가 예측하고 있었던 POST 메소드의 요청을 하지 않고 OPTIONS 요청을 하고 있음을 알게 되었다. 이것이 바로 preflight request 인 것이다. OPTIONS에서 제대로 된 응답을 주지 못하기 때문에 다음 POST 명령 자체도 실행하지 못하는 것으로 보인다.

   _server->afterRequest([](const QHttpServerRequest& request, QHttpServerResponse &&resp) {
if (request.method() == QHttpServerRequest::Method::Options) {
QHttpServerResponse respOptions{QHttpServerResponse::StatusCode::NoContent};
respOptions.addHeader("Access-Control-Allow-Origin", "http://localhost");
respOptions.addHeader("Access-Control-Allow-Methods", "GET,HEAD,PUT,PATCH,POST,DELETE");
respOptions.addHeader("Vary", "Access-Control-Request-Headers");

resp = std::move(respOptions);
}

swagger의 오류 메시지를 통해서 처음에는 CORS문제로 판단했다. CORS 관련 삽질 이야기는

에서 대충 읊었다.

설정을 해줬지만, 기대했던 대로 동작하지 않는다. 역시나 POST 요청 조차도 하지 않는다. express로 작성한 코드는 잘만 되는구만! 결국 cors 모듈을 열어 젖히고, log를 찍어봤다. 도대체 OPTIONS 요청에 해서 어떻게 응답을 주는가!

function middlewareWrapper(o) {
...
return function corsMiddleware(req, res, next) {
...
if (originCallback) {
console.log("maybe this")
originCallback(req.headers.origin, function (err2, origin) {
if (err2 || !origin) {
next(err2);
} else {
corsOptions.origin = origin;
cors(corsOptions, req, res, next);
console.log("after cors", res.getHeaders());
}
});
} else {
console.log("maybe not this");
next();
...

안쪽 if ~ else 구분의 cors() 함수 호출 부분이 정상적으로 동작할 때 실행되는 부분이다.

after cors [Object: null prototype] {
'x-powered-by': 'Express',
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
vary: 'Access-Control-Request-Headers',
'access-control-allow-headers': 'authorization',
'content-length': '0'
}

문제가 되는 부분은 바로 access-control-allow-headers 키에 대한 설정이 없기 때문인 것 같다.

해결

이제는 Qt에서 작업하던 것에 반영을 할 때이다.

    _server->afterRequest([](const QHttpServerRequest& request, QHttpServerResponse &&resp) {
if (request.method() == QHttpServerRequest::Method::Options) {
QHttpServerResponse respOptions{QHttpServerResponse::StatusCode::NoContent};
respOptions.addHeader("Access-Control-Allow-Origin", "http://localhost");
respOptions.addHeader("Access-Control-Allow-Methods", "GET,HEAD,PUT,PATCH,POST,DELETE");
respOptions.addHeader("Vary", "Access-Control-Request-Headers");
respOptions.addHeader("Access-Control-Allow-Headers", "authorization");
resp = std::move(respOptions);
}
...
return std::move(resp);

드디어 swagger 요청을 통해서도 apiKey 경로로 처리할 수 있게 되었다.

혹시 QHttpServer를 통해서 웹 서비스를 하려고 계획이 있다면 열정을 잠시 거두는 것이 좋을 것 같다. 어느 정도 Qt 버전이 업데이트 되고 QHttpServer를 지원하는 지원 모듈이나 라이브러리들이 많이 나오고 난 뒤에 시도해보는 것이 좋을 것 같다.

--

--

이상문
이상문

Written by 이상문

software developer working mainly in field of streaming, using C++, javascript

No responses yet