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.
@Kajzer133 would the following test case (which executes HTTP GET request) help?
@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!
Most helpful comment
@SonnyRajagopalan yes that's right. I'll be working on this now, sorry for the delay.