Как работает в Windows аутентификации в вебе.
Вот я создал Web Api для теста.
Обращаюсь к ValuesController
и каким-то магическим образом мои учетные данные попадают в контроллер.
Как они там оказываются? Их браузер передает? Откуда он знает, что он их должен приложить?
Как договорятся браузер и сервер о протоколе во время хендшейка.
Очень любопытно ковырять исходники owin или какого-нибудь стороннего веб-сервера попроще (я люблю NancyFX). Вот например, сервер может работать в одном из следующих режимов:
Пример кода NancyFX для доменной авторизации:
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();
}
}
}
Вероятнее всего будет Kerberos или NTLM. Да-да, я сам был удивлён, что старик ntlm до сих пор жив.
Я как-то разбирался в похожем вопросе - можете посмотреть ссылки на MSDN, где оооочень подробно расписаны все шаги по установлению протокола и формату пересылаемых сообщений.
Отдельно надо иметь ввиду, что если вы в браузере рассматриваете заголовки -- будьте готовы к тому, что хром обманывает и показывает не все.
Также отдельно нужно понимать, что во многих случаях в случае CORS-запросов перед реальным POST-запросом браузер любит отправлять предварительные заголовки OPTIONS - и это тоже поначалу сбивает с толку при отладке WebAPI. (Возможно, вы уже сталкивались? Не знаю, но упомяну)
Очень любопытно моделировать настоящий браузер из HttpClient'а и сравнивать поведение с реальным браузером - как это выглядит всё в fiddler'е (Прямо говоря, установка fiddler'а - это ещё тот танец с бубном когда речь заходит о HTTPS-протоколе, там штуки три подводных камня есть, которые придётся пройти).
Вот например для 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();
}
}
Готовим WebApi, обстреливаем:
var unit = new WebRequestHelper("AK", "password", "domain");
unit.GetAsync("https://localhost:44395/api/values").Result.Dump(); // Expected: ["value1","value2"]
А вот - для JWT мой linqpad'овский скрипт:
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; }
}
И очень хорошо подключать swagger к серверной части, чтобы смотреть за тем API, которое вы создаёте.
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Виртуальный выделенный сервер (VDS) становится отличным выбором
У меня есть игра, в которой есть разный муссорОни обладают полями типа: - тип (как индикатор, который указывает на то какие параметры будут...
Есть инструкция по написании необходимой библиотеки на C#Она гласит следующее:
При использовании конфигурации appexe
После установки CefCharp в папке сборки появились папки "x64", "x86", "GPUCache", "blob_storage"