As the browser and the server agree on the protocol during the handshake.
It is very curious to pick the source code of owin or some third-party web server easier (I love NancyFX). For example, the server can work in one of the following modes:
- Anonymous
- Basic
- Digest
- IntegratedWindowsAuthentication
- Negotiate
- None
- Ntlm
Example NancyFX code for domain authorization:
using System.Net; using Owin; namespace NancyWebApp.Nancy.Owin { public class Startup { public void Configuration(IAppBuilder app) { var listener = (HttpListener) app.Properties["System.Net.HttpListener"]; listener.AuthenticationSchemes = AuthenticationSchemes.IntegratedWindowsAuthentication; app.UseNancy(); } } }
Most likely to be Kerberos or NTLM. Yes, yes, I myself was surprised that the old man ntlm is still alive.
I somehow understood a similar question - you can see the links on MSDN, where all the steps to establish the protocol and the format of the forwarded messages are detailed in detail.
Separately, it must be borne in mind that if you are viewing the headers in the browser - be prepared for the fact that chrome is deceiving and shows not everything.
Also, you need to separately understand that in many cases, in the case of CORS requests, before the actual POST request, the browser likes to send preliminary OPTIONS headers - and this is also confusing at first when debugging the WebAPI. (Perhaps you have already encountered? I do not know, but I will mention)
It is very curious to simulate a real browser from HttpClient and compare the behavior with a real browser - it looks like everything in fiddler (Frankly, installing fiddler is also a tambourine dance when it comes to the HTTPS protocol, there are three There are underwater stones that will have to go through).
Here's an example for NTLM:
public class WebRequestHelper { public WebRequestHelper(string userName, string password, string domain) { var credentials = new NetworkCredential(userName, password, domain); var handler = new HttpClientHandler { Credentials = credentials, UseDefaultCredentials = false }; this.Client = new HttpClient(handler); } public HttpClient Client { get; set; } public async Task<string> GetAsync(string uri) { return await this.Client.GetStringAsync(uri); } public async Task<string> PostFormAsync(string uri, Dictionary<string, string> data) { var content = new FormUrlEncodedContent(data); var response = await this.Client.PostAsync(uri, content); return await response.Content.ReadAsStringAsync(); } public async Task<string> PostAsync(string uri, string jsonString) { var content = new StringContent(jsonString, Encoding.UTF8, "application/json"); var response = await this.Client.PostAsync(uri, content); return await response.Content.ReadAsStringAsync(); } }
We prepare WebApi, we fire:
var unit = new WebRequestHelper("AK", "password", "domain"); unit.GetAsync("https://localhost:44395/api/values").Result.Dump(); // Expected: ["value1","value2"]
And here is my linqpad script for JWT:
public class WebRequestHelper { public async Task<string> GetAsync(string uri) { var client = new HttpClient(); return await client.GetStringAsync(uri); } public async Task<string> PostFormAsync(string uri, Dictionary<string, string> data) { var client = new HttpClient(); var content = new FormUrlEncodedContent(data); var response = await client.PostAsync(uri, content); return await response.Content.ReadAsStringAsync(); } public async Task<string> PostAsync(string uri, string jsonString) { var client = new HttpClient(); var content = new StringContent(jsonString, Encoding.UTF8, "application/json"); var response = await client.PostAsync(uri, content); return await response.Content.ReadAsStringAsync(); } public async Task<Token> GetToken(string tokenUrl, string username, string password) { var data = new Dictionary<string, string> { { "username", username }, { "password", password }, }; var answer = await this.PostFormAsync(tokenUrl, data); if(string.Equals(answer, "Invalid username or password.")) return null; return JsonConvert.DeserializeObject<Token>(answer); } public async Task<string> GetWithJwtAsync(string uri, Token token) { var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Value); return await client.GetStringAsync(uri); } public async Task<string> PostFormWithJwtAsync(string uri, Dictionary<string, string> data, Token token) { var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("JWT", token.Value); var content = new FormUrlEncodedContent(data); var response = await client.PostAsync(uri, content); return await response.Content.ReadAsStringAsync(); } public async Task<string> PostWithJwtAsync(string uri, string jsonString, Token token) { var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Value); var content = new StringContent(jsonString, Encoding.UTF8, "application/json"); var response = await client.PostAsync(uri, content); return await response.Content.ReadAsStringAsync(); } } public class Token { [JsonProperty("access_token")] public string Value { get; set; } [JsonProperty("username")] public string UserName { get; set; } }
And it's very good to connect the swagger to the server side to look at the API you are creating.
Basic
orDigest
http authorization to a specific address passes, and you have visited this resource before, logged in and saved the password .. :) And in the webApi settings, authorization is set using attributes, check this point. - NewViewNTLM
. - EvgeniyZ