C# HttpClient Authentication and Data Transmission Notes

2019年12月15日 88点热度 0人点赞 0条评论
内容目录

C# HttpClient Request Authentication and Data Transmission Notes

[TOC]

I. Authorization Authentication

When a client requests a server, authorization authentication is required to obtain server resources. Currently, common authentication methods include Basic, JWT, and Cookie.

HttpClient is the HTTP/HTTPS client in C# used for sending HTTP requests and receiving HTTP responses from resources identified by a URI. The following is a demonstration with specific code.

1. Basic Authentication Example

        // Basic Authentication
        public async Task Basic(string user, string password, string url)
        {
            // If the authentication page is HTTPS, refer to the JWT authentication's HttpClientHandler
            // Create client 
            HttpClient client = new HttpClient();

            // Create authentication
            // using System.Net.Http.Headers;
            AuthenticationHeaderValue authentication = new AuthenticationHeaderValue(
                "Basic",
                Convert.ToBase64String(Encoding.UTF8.GetBytes($"{user}:{password}")
                ));

            client.DefaultRequestHeaders.Authorization = authentication;

            byte[] response = await client.GetByteArrayAsync(url);
            client.Dispose();
        }

As can be seen, Basic authentication has a very low level of security, predominantly used for routers and embedded devices, and often does not utilize HTTPS.

2. JWT Authentication Example

        // JWT Authentication
        public async Task Bearer(string token, string url)
        {
            // HttpClientHandler and its derived classes allow developers to configure various options, including proxies and authentication.
            // helpLink https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclienthandler?view=netframework-4.8
            var httpclientHandler = new HttpClientHandler();

            // If the server has an HTTPS certificate but the certificate is not secure, use the statement below
            // => That is, do not validate the certificate and allow directly
            httpclientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true;

            using (var httpClient = new HttpClient(httpclientHandler))
            {
                // Create authentication
                // System.Net.Http.Headers.AuthenticationHeaderValue;
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
                await httpClient.GetAsync(url);
                httpClient.Dispose();
            }
        }

JWT authentication requires the client to carry a token, which is a string that has been encrypted. The principle will not be discussed here; the token is carried via the client header.

Additionally, for testing web applications or intranet applications, the HTTPS certificate might not be a publicly internationally certified certificate, and thus the validation needs to be skipped to allow direct access.

            var httpclientHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true,
            };

3. Cookie Example

In HttpClient, there are two ways to handle Cookies.

One method involves already knowing the Cookie and directly storing it in the HttpClient; the other involves not having the Cookie yet, logging in with a username and password to obtain the Cookie, which is then automatically stored in the HttpClient instance for making requests.

The setting for both methods is done through the UseCookies property of HttpClientHandler.

Example

            var httpclientHandler = new HttpClientHandler()
            {
                UseCookies = true
            };

UseCookies gets or sets a value that indicates whether the handler uses the CookieContainer property to store server Cookies and sends these Cookies with requests.

Method 1:

        // Log in with username and password before requesting
        public async Task Cookie(string user, string password, string loginUrl, string url)
        {
            var httpclientHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true,
                UseCookies = true
            };
            // If the server has an HTTPS certificate but the certificate is not secure, use the statement below
            // => That is, do not validate the certificate and allow directly

            var loginContent = new FormUrlEncodedContent(new[] 
            {
                new KeyValuePair<string, string>("user", user),
                new KeyValuePair<string, string>("password", password)
            });

            using (var httpClient = new HttpClient(httpclientHandler))
            {
                // First log in
                var result = await httpClient.PostAsync(loginUrl, loginContent);
                // After a successful login, the client will automatically carry the Cookie without needing to add it manually
                // if (result.IsSuccessStatusCode)
                // {
                //     /*
                //      * If the request is successful
                //      */
                // }

                var result2 = await httpClient.GetAsync(url);
                // httpClient has already carried the Cookie and can be reused multiple times
                // var result3 = await httpClient.GetAsync(url3);
                // var result4 = await httpClient.GetAsync(url4);
                httpClient.Dispose();
            }
        }

Method 2:

        // Already obtained Cookie, directly use Cookie to request
        public async Task Cookie(string cookie, string url)
        {
            var httpclientHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true,
                UseCookies = false
            };
            // If the server has an HTTPS certificate but the certificate is not secure, use the statement below
            // => That is, do not validate the certificate and allow directly

            using (var httpClient = new HttpClient(httpclientHandler))
            {
                httpClient.DefaultRequestHeaders.Add("Cookie", cookie);
                await httpClient.GetAsync(url);
                httpClient.Dispose();
            }
        }

II. Request Types

In HTTP requests, there are various types such as GET, POST, DELETE, PUT, etc.

In HttpClient, the following request-related methods are available:

  1. CancelPendingRequests
  2. DeleteAsync
  3. GetAsync
  4. GetByteArrayAsync
  5. GetStreamAsync
  6. GetStringAsync
  7. PostAsync
  8. PutAsync
  9. SendAsync

Among these, CancelPendingRequests cancels all pending requests for the instance and is not a request type.

SendAsync is used for handling an HttpRequestMessage (representing an HTTP request message), which is more raw.

s

For methods like GetAsync, PostAsync, the usage process is similar; below is an example of use.

        public async void Request(string url)
        {
            using (var httpClient = new HttpClient())
            {
                // In HttpClient, all GET requests are asynchronous
                HttpResponseMessage result = await httpClient.GetAsync(url);

                // Task<T>.Result can obtain the asynchronous result
                result = httpClient.GetAsync(url).Result;

                // var result1 = await httpClient.GetByteArrayAsync(url);
                // var result1 = await httpClient.GetStreamAsync(url);
                // var result1 = await httpClient.GetStringAsync(url);

                // ByteArrayContent

                FormUrlEncodedContent fromContent = new FormUrlEncodedContent(new[]
                {
                    new KeyValuePair<string, string>("Email", "123@qq.com"),
                    new KeyValuePair<string, string>("Number", "666")
                });
                // When using POST, it is necessary to carry an object that inherits from HttpContent
                // This means that POST must upload data
                result = await httpClient.PostAsync(url, fromContent);

                // If there is no data to upload, null can be used
                result = await httpClient.PostAsync(url, null);

                httpClient.Dispose();
            }

III. Data Transmission

In HTTP/HTTPS requests, data is often transmitted along with it, such as form submissions, JSON uploads, file uploads, etc. Below is a demonstration with code.

1. Query

The ASP.NET Core API can be written like this:

        [HttpPost("aaa")]
        public async Task<JsonResult> AAA(int? a, int? b)
        {
            if (a == null || b == null)
                return new JsonResult(new { code = 0, result = "aaaaaaaa" });
            return new JsonResult(new { code = 2000, result = a + "|" + b });
        }

HttpClient:

        // URL Query parameters
        public void Query(string a, string b)
        {
            var httpclientHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true,
            };
            using (var httpClient = new HttpClient(httpclientHandler))
            {

                var result = httpClient.PostAsync($"https://localhost:5001/test?a={a}&b={b}", null).Result;

                httpClient.Dispose();
            }
        }

2. Header

Headers are stored in key-value pairs. Here is an HttpClient example:

        // Header
        public void Header()
        {
            var httpclientHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true,
            };
            using (var httpClient = new HttpClient(httpclientHandler))
            {
                httpClient.DefaultRequestHeaders.Add("MyEmail", "123@qq.com");
                var result = httpClient.GetAsync($"https://localhost:5001/test").Result;

                httpClient.Dispose();
            }
        }

ASP.NET Core API example:

        [HttpPost("ddd")]
        public async Task<JsonResult> DDD([FromHeader]int? a, [FromHeader]int? b)
        {
            if (a == null || b == null)
                return new JsonResult(new { code = 0, result = "aaaaaaaa" });
            return new JsonResult(new { code = 200, result = a + "|" + b });
        }

3. Form

        // Form submission
        // application/x-www-form-urlencoded
        public void From()
        {
            var httpclientHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true,
            };

            var fromContent = new FormUrlEncodedContent(new[]
            {
             new KeyValuePair<string,string>("Id","1"),
             new KeyValuePair<string,string>("Name","whuanle"),
             new KeyValuePair<string, string>("Number","666666")
            });

            using (var httpClient = new HttpClient(httpclientHandler))
            {
                var result = httpClient.PostAsync("https://localhost:5001/test", fromContent).Result;

                Console.WriteLine(result.Content.ReadAsStringAsync().Result);
                httpClient.Dispose();
            }
        }

4. JSON

In addition to JSON, there are also:

  • text/html
  • application/javascript
  • text/plain
  • application/xml

They are all represented using StringContent.

        // JSON and others
        public void StringAnd(string json)
        {
            var httpclientHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true,
            };

            var jsonContent = new StringContent(json);

            // JSON is represented as StringContent, and during upload, the Content-Type property should be specified. Additionally:
            // text/html
            // application/javascript
            // text/plain
            // application/xml
            jsonContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");

            using (var httpClient = new HttpClient(httpclientHandler))
            {

                var result = httpClient.PostAsync("https://localhost:5001/test", jsonContent).Result;

                Console.WriteLine(result.Content.ReadAsStringAsync().Result);
                httpClient.Dispose();
            }
        }

5. Upload File

The API is written like this:

        [HttpPost] // Uploading files is done via POST; it can be included or omitted
        public async Task<IActionResult> UploadFiles(List<IFormFile> files)
        {
            // ...
        }

HttpClient implementation:

        // File upload
        public async Task File(string filepath, string fromName, string url)
        {
            using (var client = new HttpClient())
            {
                FileStream imagestream = System.IO.File.OpenRead(filepath);
                // multipartFormDataContent.Add();
                var multipartFormDataContent = new MultipartFormDataContent()
                {
                    {
                        new ByteArrayContent(System.IO.File.ReadAllBytes(filepath)),    // File stream
                        fromName,                                                       // Corresponding parameter for the server WebAPI
                        Path.GetFileName(filepath)                                      // Uploaded file name
                    }
                };
                /* 
                 * If the server API is written as
                 * ([FromForm]IFromFile files)
                 * then fromName="files" above
                 */
                // multipartFormDataContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");

                HttpResponseMessage response = await client.PostAsync(url, multipartFormDataContent);
                if (!response.IsSuccessStatusCode)
                {

                    Console.WriteLine("Up image error");
                    Console.WriteLine(response.RequestMessage);
                }
            }
        }

痴者工良

高级程序员劝退师

文章评论