1

我有一个可用的libsoup客户端,它使用 HTTP POST 和基本身份验证发送数据。身份验证是libsoup通过回调处理的——当服务器需要身份验证时,通过回调libsoup向它发出信号——然后该函数将传递给SoupAuthsoup_auth_authenticate()类型的给定对象以及用户名和密码。

#include <iostream>
#include <iomanip>
#include <string>
#include <libsoup/soup.h>
using namespace std;

void authenticate(SoupSession *session, SoupMessage *msg, SoupAuth *auth, gboolean retrying, gpointer data) {
    soup_auth_authenticate(auth, "foo", "bar");
}

int main() {
    SoupSession* session = soup_session_new_with_options(SOUP_SESSION_USER_AGENT, "stackoverflow",
                                                         SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_COOKIE_JAR,
                                                         NULL);
    g_signal_connect(session, "authenticate", G_CALLBACK(authenticate), nullptr);
    SoupMessage* post_msg = soup_message_new("POST", "https://example.org/work.php");
    string formdata = "first_name=Captain&last_name=Picard";
    soup_message_set_request(post_msg, "application/x-www-form-urlencoded", SOUP_MEMORY_COPY, formdata.c_str(), formdata.size());
    soup_session_send_message(session, post_msg);
    cout << left << setw(22) << "status code: " << right << post_msg->status_code << "\n";
    cout << left << setw(22) << "reason phrase: " << right << post_msg->reason_phrase << "\n";
    cout << left << setw(22) << "response body length: " << right << post_msg->response_body->length << "\n";
    cout << left << setw(22) << "response body data: " << right << post_msg->response_body->data << "\n";
    // TODO call soup_session_send_message() again with modified username and password
    return EXIT_SUCCESS;
}

你可以用g++ -o sample sample.cpp -Wall -pedantic -g `pkg-config libsoup-2.4 --cflags --libs`. 当您需要对此进行测试时,请更改为您提供工作端点的example.orgflapflap.eu

当我想在后续呼叫中发送不同的用户名或密码时,我应该怎么做?该库将不再使用回调,因为身份验证已设置并正在工作。

我需要创建一个新的SoupSession吗?或者我可以访问当前SoupAuthsoup_auth_authenicate()直接调用吗?我想让客户快速工作。

谢谢您的帮助

4

1 回答 1

1

底部的背景信息表明您不需要创建一个新SoupSession的来进行后续的身份验证请求。尚不清楚soup_auth_authenticate()调用是否是执行此操作的方法。以下是此libsoup页面中与身份验证相关的调用列表:

SoupAuth *  soup_auth_new ()
gboolean    soup_auth_update ()
gboolean    soup_auth_negotiate_supported ()
gboolean    soup_auth_is_for_proxy ()
const char *    soup_auth_get_scheme_name ()
const char *    soup_auth_get_host ()
const char *    soup_auth_get_realm ()
char *  soup_auth_get_info ()
void    soup_auth_authenticate ()
gboolean    soup_auth_can_authenticate ()
gboolean    soup_auth_is_authenticated ()
gboolean    soup_auth_is_ready ()
char *  soup_auth_get_authorization ()
GSList *    soup_auth_get_protection_space ()
void    soup_auth_free_protection_space ()

在此Basics 页面中的各行之间阅读似乎表明可以在单个SoupSession.

处理认证

SoupSession 为您处理 HTTP 身份验证的大部分细节。如果收到 401(“未授权”)或 407(“需要代理身份验证”)响应,会话将发出身份验证信号,为您提供指示身份验证类型(“基本”、“摘要”或“ NTLM") 和服务器提供的领域名称。如果您有可用的用户名和密码(或可以生成一个),请调用 soup_auth_authenticate 将信息提供给 libsoup。会话将自动重新排队消息并使用该身份验证信息再次尝试。(如果你不调用soup_auth_authenticate,会话只会将消息返回给应用程序,其状态为401或407。)

如果服务器不接受提供的用户名和密码,会话将再次发出身份验证,重试参数设置为 TRUE。这让应用程序知道它之前提供的信息不正确,并给它一个重试的机会。如果这个用户名/密码对也不起作用,会话将继续一次又一次地发出身份验证,直到提供的用户名/密码成功通过身份验证,或者直到信号处理程序未能调用 soup_auth_authenticate,此时 libsoup 将允许消息失败(状态为 401 或 407)。

如果您需要异步处理身份验证(例如,在不递归进入主循环的情况下弹出密码对话框),您也可以这样做。在从信号处理程序返回之前,只需在消息上调用 soup_session_pause_message,然后 g_object_ref 调用 SoupAuth。然后,稍后,在调用soup_auth_authenticate(或决定不这样做)之后,调用soup_session_unpause_message 以恢复暂停的消息。

这篇 Manpagez 帖子还讨论了对每个会话进行身份验证的多个调用:

大多数应用程序只需要一个 SoupSession;您可能需要多个会话的主要原因是您是否需要多个独立的身份验证上下文。(例如,您正在连接到服务器并在不同的时间以两个不同的用户身份进行身份验证;确保每个 SoupMessage 都与您想要的身份验证信息一起发送的最简单方法是为第一个用户使用一个会话,为第一个用户使用第二个会话另一个用户。)

于 2020-06-04T13:25:44.110 回答