You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Maui中如何通过HTTP Cookie向Web API发送JSON登录信息?

API认证规则

该API采用HTTP Cookie进行身份验证。
首次调用任何无需身份验证的GET API端点(推荐使用/api/_initial),会返回后续认证请求所需的SID(会话ID)Cookie和csrftoken Cookie。
除GET请求外,所有请求需将csrftoken Cookie的值放入X-Csrf-Token HTTP请求头中,以防范跨站请求伪造。
/api/_login [POST] 请求的JSON体必须如下:

{
     "username": string,
     "password": string 
}

若用户名和密码匹配,将返回用户对象;否则返回401(未授权)错误。

问题描述

我编写的代码虽使用有效凭据,但调用登录接口时仍返回401 Unauthorized错误。目前尚未完善LoginData类的实现,仅希望先实现最基础的功能,之后再迁移到MVVM架构。以下是我的初始代码:

using System.Net;
using System.Net.Http.Headers;
using System.Net.Http.Json;

namespace App.Views;

public class LoginData
{
    [JsonPropertyName("username")] public string Username { get; set; }
    [JsonPropertyName("password")] public string Password { get; set; }
}

public partial class SubscriptionsPage : ContentPage
{
    public SubscriptionsPage()
    {
        InitializeComponent();

        //set url for api endpoint to initialize session and retrieve SID and CSRF tokens
        var uri = new Uri("https://discuit.net/api/_initial");

        //create http client and request message to obtain SID and CSRF token from response headers
        var httpClient = new HttpClient();
        var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri);
        var httpResponseMessage = httpClient.SendAsync(httpRequestMessage).Result;

        //get response headers to retrieve Session ID and CSRF token
        var headersResult = httpResponseMessage.Headers;

        //get Session ID and CSRF token into variables
        var cookies = httpResponseMessage.Headers.GetValues("Set-Cookie");

        var cookieList = new List<string>();

        //store the needed cookies in a variable for use in POST url
        foreach (var cookie in cookies)
        {
            // Split the cookie string by ';'
            var parts = cookie.Split(';');

            // Get the first part, which contains the name and value
            var nameValue = parts[0];

            //add each part to the cookieList List
            cookieList.Add(nameValue);
        }
        
        //store each part into a variable to add to the cookies for the POST request
        var SID = cookieList[0];
        var csrftoken = cookieList[1];

        Console.WriteLine("-----------------------------------------");
        Console.WriteLine("SID: " + SID);
        Console.WriteLine("csrftoken: " + csrftoken);
        Console.WriteLine("-----------------------------------------");

        // set url to login endpoint
        var url = new Uri("https://discuit.net/api/_login");

        // create a cookie container and add the cookies to it so we can send a POST request to login
        var cookieContainer = new CookieContainer();
        var handler = new HttpClientHandler() { CookieContainer = cookieContainer };
        var client = new HttpClient(handler);

        Console.WriteLine("-----------------------------------------");
        Console.WriteLine("Adding Cookies to CookieContainer");
        Console.WriteLine("-----------------------------------------");

        // add the cookies to the cookie container
        cookieContainer.Add(url, new Cookie("SID", SID));
        cookieContainer.Add(url, new Cookie("csrftoken", csrftoken));

        Console.WriteLine("-----------------------------------------");
        Console.WriteLine("Creating JSON Data");
        Console.WriteLine("-----------------------------------------");

        //create sample json with valid credentials
        //TODO: Get credentials from login page/use LoginData class
        var login = new LoginData { Username = "testaccount", Password = "testpassword" };

        // send json login request to server using new http client with handler with SID and csrftoken added as cookies
        Console.WriteLine("-----------------------------------------");
        Console.WriteLine("Posting Data...");
        Console.WriteLine("URL: " + url);
        Console.WriteLine("Data: " + login);
        Console.WriteLine("-----------------------------------------");
        var result = client.PostAsJsonAsync(url, login).Result;

        if(result.IsSuccessStatusCode)
        {
            Console.WriteLine("-----------------------------------------");
            Console.WriteLine("RESULT: " + result);
            Console.WriteLine("-----------------------------------------");
            // TODO: Return token
        }
        else
        {
            Console.WriteLine("-----------------------------------------");
            Console.WriteLine($"The web API returned an error: {result.StatusCode}");
            Console.WriteLine("-----------------------------------------");
            Console.WriteLine("-----------------------------------------");
            Console.WriteLine("RESULT: " + result);
            Console.WriteLine("-----------------------------------------");
        }
    }
}

运行输出

> [DOTNET] -----------------------------------------
> [DOTNET] SID: SID=qP7salkaN7qyWpLWsZcaK7akvx728b9Vij00
> [DOTNET] csrftoken: csrftoken=Fa9MJF8iA3y6i-NaZOasSelQjd0Kue8Hg7H7aEy6-x0=
> [DOTNET] -----------------------------------------
> [DOTNET] -----------------------------------------
> [DOTNET] Adding Cookies to CookieContainer
> [DOTNET] -----------------------------------------
> [DOTNET] -----------------------------------------
> [DOTNET] Creating JSON Data
> [DOTNET] -----------------------------------------
> [DOTNET] -----------------------------------------
> [DOTNET] Posting Data...
> [DOTNET] URL: https://example.net/api/_login
> [DOTNET] Data: Disc.Views.LoginData
> [DOTNET] -----------------------------------------
> [DOTNET] -----------------------------------------
> [DOTNET] The web API returned an error: Unauthorized
> [DOTNET] -----------------------------------------
> [DOTNET] -----------------------------------------
> [DOTNET] RESULT: StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
> [DOTNET] {
> [DOTNET]   Cache-Control: no-store
> [DOTNET]   Date: Wed, 26 Jul 2023 18:32:39 GMT
> [DOTNET]   Set-Cookie: SID=15ka07TA3UqoNWjU46mmCiiOdOJFEPXLFxcy; Path=/; Expires=Sat, 20 Jul 2024 18:32:39 GMT; HttpOnly; Secure; SameSite=Lax
> [DOTNET]   X-Android-Received-Millis: 1690396360195
> [DOTNET]   X-Android-Response-Source: NETWORK 401
> [DOTNET]   X-Android-Selected-Protocol: http/1.1
> [DOTNET]   X-Android-Sent-Millis: 1690396360118
> [DOTNET]   Content-Length: 39
> [DOTNET]   Content-Type: application/json; charset=UTF-8
> [DOTNET] }
> [DOTNET] -----------------------------------------

总结

我尝试向API传递登录数据以获取200成功响应及用户对象,但始终收到401未授权错误。参考已采纳的解决方案后,我得到了可正常运行的代码,接下来将把它迁移到MVVM架构中:

using System.Net;
using System.Net.Http.Json;
using System.Text.Json.Serialization;

namespace App.Views;

public class LoginData
{
    [JsonPropertyName("username")] public string Username { get; set; }
    [JsonPropertyName("password")] public string Password { get; set; }
}

public partial class SubscriptionsPage : ContentPage
{
    public SubscriptionsPage()
    {
        InitializeComponent();

        // set url for api endpoint to initialize session
        var uri = new Uri("https://discuit.net/api/_initial");

        // create http client and request message to obtain SID and CSRF token from response headers
        HttpClientHandler handler = new HttpClientHandler();
        handler.UseCookies = true;
        handler.CookieContainer = new CookieContainer();
        HttpClient client = new HttpClient(handler);

        HttpResponseMessage repsonse = client.GetAsync(uri).Result;
        CookieCollection cookies = handler.CookieContainer.GetCookies(uri);

        // create new Dictionary to store cookie data
        var cookieList = new Dictionary<string, string>();

        // get Session ID and CSRF token into variables
        foreach ( Cookie cookie in cookies)
        {
            cookieList.Add(cookie.Name, cookie.Value);
        }

        var SID = cookieList["SID"];
        var csrftoken = cookieList["csrftoken"];

        // new variable url set to login endpoint
        var url = new Uri("https://discuit.net/api/_login");

        // create a cookie container and add the SID to the api/_login url
        CookieContainer cookieContainer = new CookieContainer();
        cookieContainer.Add(url, new Cookie("SID", SID));

        // Add X-CSRF-Token to client
        client.DefaultRequestHeaders.Add("x-csrf-token", csrftoken);

        // create sample json with valid credentials
        // TODO: Get credentials from login page once this is working
        var login = new LoginData { Username = "testaccount", Password = "testpassword" };

        // send json login request to server using new http client with handler
        var result = client.PostAsJsonAsync(url, login).Result;
        
        if(result.IsSuccessStatusCode)
        {
            Console.WriteLine("-----------------------------------------");
            Console.WriteLine("StatusCode: " + result.StatusCode);
            Console.WriteLine("RESULT: " + result);
            Console.WriteLine("-----------------------------------------");
            // TODO: Return token
        }
        else
        {
            Console.WriteLine("-----------------------------------------");
            Console.WriteLine($"The web API returned an error: {result.StatusCode}");
            Console.WriteLine("-----------------------------------------");
            Console.WriteLine("-----------------------------------------");
            Console.WriteLine("RESULT: " + result);
            Console.WriteLine("-----------------------------------------");
        }
        
    }
}

内容的提问来源于stack exchange,提问作者ReticentRobot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 18:57:07