Swagger-codegen: [QT5 C++] JSON Token authorization problem / setting header

Created on 10 Mar 2017  路  9Comments  路  Source: swagger-api/swagger-codegen

  • Version of Swagger: 2.2.2

Issue

Problem with json token authorization. I use CakePHP REST Api in project. The are a lot of tables in our MSSQL database. I want to set header for each by return token from SWGAuthenticateApi and pass it in main class, before calling, by variable for example: to object, which method inserts new data to table. Currently I use request.setRawHeader("Authorization", "here I wrote a token statically") in SWGHttpRequest.cpp. I want token to be valid only for 2h so I can't write it manually in my application. I know that i can use:

HttpRequestWorker *worker = new HttpRequestWorker(); HttpRequestInput input(fullPath, "POST"); input.headers.insert("Authorization","");

But the problem is that i can't or i don't know how to return token to my main class and add configuration. All functions are void, and there is no configuration method too. Is there an option to generate a code in Qt without void functions but with functions that return something? Or maybe there is a way to do it on voids?

In C# Client it looks like:

IrisCodeResponse result = loginApiInstance.ApiLoginPost(login); token = result.Data.Token; token = String.Format("bearer {0}", token); apiInstance.Configuration.AddDefaultHeader("authorization", token);

I want to make it similar to this, in QT.

C++ Question

Most helpful comment

@SonnyRajagopalan yes that's right. I'll be working on this now, sorry for the delay.

All 9 comments

@Kajzer133 would the following test case (which executes HTTP GET request) help?

https://github.com/swagger-api/swagger-codegen/blob/master/samples/client/petstore/qt5cpp/PetStore/PetApiTests.cpp#L66

@wing328 sorry for my late feedback, but i had more things to do.

I don't see authorization test in Your example. I think this is only test of post and get. I use SWGAuthenticateApi to get JSON Web-authorization token and I am able to Insert new data, but only when I modfiy original classess and I use token statically.

How can I pass the JSON-Web-Token Authorization header to every request? The only solution I find is to edit the generated files but this is not useful in future.

Anyone an idea? We set securitydefinitions and add it to your requests

"securityDefinitions": {
    "jwt": {
        "type": "apiKey",
        "name": "Auth",
        "in": "header"
    }
}

But we do not find any possibility to add these information to our requests. In SWGHttpRequest there is the methode

void HttpRequestWorker::execute(HttpRequestInput *input) {

    // reset variables

    QByteArray request_content = "";
    response = "";
    error_type = QNetworkReply::NoError;
    error_str = "";
    bool isFormData = false;


    // decide on the variable layout

    if (input->files.length() > 0) {
        input->var_layout = MULTIPART;
    }
    if (input->var_layout == NOT_SET) {
        input->var_layout = input->http_method == "GET" || input->http_method == "HEAD" ? ADDRESS : URL_ENCODED;
    }


    // prepare request content

    QString boundary = "";

    if (input->var_layout == ADDRESS || input->var_layout == URL_ENCODED) {
        // variable layout is ADDRESS or URL_ENCODED

        if (input->vars.count() > 0) {
            bool first = true;
            isFormData = true;
            foreach (QString key, input->vars.keys()) {
                if (!first) {
                    request_content.append("&");
                }
                first = false;

                request_content.append(QUrl::toPercentEncoding(key));
                request_content.append("=");
                request_content.append(QUrl::toPercentEncoding(input->vars.value(key)));
            }

            if (input->var_layout == ADDRESS) {
                input->url_str += "?" + request_content;
                request_content = "";
            }
        }
    }
    else {
        // variable layout is MULTIPART

        boundary = "__-----------------------"
            + QString::number(QDateTime::currentDateTime().toTime_t())
            + QString::number(qrand());
        QString boundary_delimiter = "--";
        QString new_line = "\r\n";

        // add variables
        foreach (QString key, input->vars.keys()) {
            // add boundary
            request_content.append(boundary_delimiter);
            request_content.append(boundary);
            request_content.append(new_line);

            // add header
            request_content.append("Content-Disposition: form-data; ");
            request_content.append(http_attribute_encode("name", key));
            request_content.append(new_line);
            request_content.append("Content-Type: text/plain");
            request_content.append(new_line);

            // add header to body splitter
            request_content.append(new_line);

            // add variable content
            request_content.append(input->vars.value(key));
            request_content.append(new_line);
        }

        // add files
        for (QList<SWGHttpRequestInputFileElement>::iterator file_info = input->files.begin(); file_info != input->files.end(); file_info++) {
            QFileInfo fi(file_info->local_filename);

            // ensure necessary variables are available
            if (
                file_info->local_filename == nullptr || file_info->local_filename.isEmpty()
                || file_info->variable_name == nullptr || file_info->variable_name.isEmpty()
                || !fi.exists() || !fi.isFile() || !fi.isReadable()
            ) {
                // silent abort for the current file
                continue;
            }

            QFile file(file_info->local_filename);
            if (!file.open(QIODevice::ReadOnly)) {
                // silent abort for the current file
                continue;
            }

            // ensure filename for the request
            if (file_info->request_filename == nullptr || file_info->request_filename.isEmpty()) {
                file_info->request_filename = fi.fileName();
                if (file_info->request_filename.isEmpty()) {
                    file_info->request_filename = "file";
                }
            }

            // add boundary
            request_content.append(boundary_delimiter);
            request_content.append(boundary);
            request_content.append(new_line);

            // add header
            request_content.append(QString("Content-Disposition: form-data; %1; %2").arg(
                http_attribute_encode("name", file_info->variable_name),
                http_attribute_encode("filename", file_info->request_filename)
            ));
            request_content.append(new_line);

            if (file_info->mime_type != nullptr && !file_info->mime_type.isEmpty()) {
                request_content.append("Content-Type: ");
                request_content.append(file_info->mime_type);
                request_content.append(new_line);
            }

            request_content.append("Content-Transfer-Encoding: binary");
            request_content.append(new_line);

            // add header to body splitter
            request_content.append(new_line);

            // add file content
            request_content.append(file.readAll());
            request_content.append(new_line);

            file.close();
        }

        // add end of body
        request_content.append(boundary_delimiter);
        request_content.append(boundary);
        request_content.append(boundary_delimiter);
    }

    if(input->request_body.size() > 0) {
        qDebug() << "got a request body";
        request_content.clear();
        request_content.append(input->request_body);
    }
    // prepare connection

    QNetworkRequest request = QNetworkRequest(QUrl(input->url_str));
    request.setRawHeader("User-Agent", "Swagger-Client");
    foreach(QString key, input->headers.keys()) {
        request.setRawHeader(key.toStdString().c_str(), input->headers.value(key).toStdString().c_str());
    }

    if (request_content.size() > 0 && !isFormData) {
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    }
    else if (input->var_layout == URL_ENCODED) {
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
    }
    else if (input->var_layout == MULTIPART) {
        request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + boundary);
    }

    if (input->http_method == "GET") {
        manager->get(request);
    }
    else if (input->http_method == "POST") {
        manager->post(request, request_content);
    }
    else if (input->http_method == "PUT") {
        manager->put(request, request_content);
    }
    else if (input->http_method == "HEAD") {
        manager->head(request);
    }
    else if (input->http_method == "DELETE") {
        manager->deleteResource(request);
    }
    else {
        QBuffer buff(&request_content);
        manager->sendCustomRequest(request, input->http_method.toLatin1(), &buff);
    }

}

It contains some code to add the header from input:

    foreach(QString key, input->headers.keys()) {
        request.setRawHeader(key.toStdString().c_str(), input->headers.value(key).toStdString().c_str());
    }

The execute method is called by the following generated code:

void
SWGV1Api::apiV1ExampleJsonPost(SWGV1example example, QString* token) {
    QString fullPath;
    fullPath.append(this->host).append(this->basePath).append("/api/v1/example.json");


    if (fullPath.indexOf("?") > 0) 
      fullPath.append("&");
    else 
      fullPath.append("?");
    fullPath.append(QUrl::toPercentEncoding("token"))
        .append("=")
        .append(QUrl::toPercentEncoding(stringValue(token)));


    HttpRequestWorker *worker = new HttpRequestWorker();
    HttpRequestInput input(fullPath, "POST");


    QString output = example.asJson();
    input.request_body.append(output);



    connect(worker,
            &HttpRequestWorker::on_execution_finished,
            this,
            &SWGV1Api::apiV1ExampleJsonPostCallback);

    worker->execute(&input);
}

Wen can call SWGV1Api::apiV1ExampleJsonPost, too. But how can we add a header with the authentication?

\cc @wing328

It looks like we didn't expose a method to set headers in the API classes. I'll see that it's added--the current generated code for setting headers is when they're declared in the operation, not the security definition.

@fehguy Is this the issue I am seeing in https://github.com/swagger-api/swagger-codegen/issues/5188? Any pointers appreciated. I am gating on this, and would like a way forward. Thanks!

@SonnyRajagopalan yes that's right. I'll be working on this now, sorry for the delay.

@fehguy Any news to this bug?

@fehguy do you know if this will be fixed in 2.2.3 or 2.3.0?

I'm really sorry about lagging. Honestly my QT got really rusty, but now it's back :)

I have the fix (it's literally 3 lines) and will try to get it in the 2.2.3 which was delayed today for other reasons. Maybe it's cosmic and I need to fix this first!

Was this page helpful?
0 / 5 - 0 ratings