.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
相关产品推荐
相关产品推荐

