Самостоятельный хост веб-API ASP.NET с аутентификацией Windows
Я пытаюсь использовать параметр Self-Host ASP.NET Web API с проверкой подлинности Windows, поэтому я могу определить зарегистрированного пользователя и в конечном итоге принять или отклонить пользователя в зависимости от их личности. Вот мой код консольного приложения:
using System;
using System.Web.Http;
using System.Web.Http.SelfHost;
namespace SelfHost
{
class Program
{
static void Main(string[] args)
{
var config = new HttpSelfHostConfiguration("http://myComputerName:8080");
config.UseWindowsAuthentication = true;
config.Routes.MapHttpRoute(
"API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional });
using (HttpSelfHostServer server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
Console.WriteLine("Press Enter to quit.");
Console.ReadLine();
}
}
}
}
Вот контроллер:
[Authorize]
public class HelloController : ApiController
{
public string Get()
{
// This next line throws an null reference exception if the Authorize
// attribute is commented out.
string userName = Request.GetUserPrincipal().Identity.Name;
return "Hello " + userName;
}
}
Изменить - я добавил атрибут Authorize, и отладчик показывает, что код внутри метода действия Get никогда не вызывается. Возвращается следующий HTML:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META content="text/html; charset=windows-1252" http-equiv=Content-Type></HEAD>
<BODY></BODY></HTML>
Если атрибут Authorize закомментирован, Request.GetUserPrincipal().Identity.Name
выдает исключение нулевой ссылки, так как Request.GetUserPrincipal()
дает значение null.
Ответы
Ответ 1
Я тоже попал в эту проблему, и единственным решением, которое я придумал, является предоставление выделенной HttpSelfHostedConfiguration:
public class NtlmSelfHostConfiguration : HttpSelfHostConfiguration
{
public NtlmSelfHostConfiguration(string baseAddress)
: base(baseAddress)
{ }
public NtlmSelfHostConfiguration(Uri baseAddress)
: base(baseAddress)
{ }
protected override BindingParameterCollection OnConfigureBinding(HttpBinding httpBinding)
{
httpBinding.Security.Mode = HttpBindingSecurityMode.TransportCredentialOnly;
httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
return base.OnConfigureBinding(httpBinding);
}
}
Чтобы использовать его, вам просто нужно изменить одну строку (вам больше не нужно устанавливать UseWindowsAuthentication):
var config = new NtlmSelfHostConfiguration("http://myComputerName:8080");
Единственная проблема с этим подходом заключается в том, что теперь требуется проверка подлинности для каждого запроса, сделанного сервером, который использует эту конфигурацию.
Ответ 2
Я разместил "Web API" в службе Windows, и это то, что я сделал для поддержки проверки подлинности Windows (в основном на основе вышеуказанного вопроса, ответов, некоторых связанных статей - я просто консолидирую, поскольку это может быть полезно для других)
@Сервер HTTTP (веб-api):
Установить (ссылка: http://msdn.microsoft.com/en-us/library/system.web.http.selfhost.httpselfhostconfiguration.clientcredentialtype( v = vs .118).aspx),
HttpSelfHostConfiguration.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Windows;
@Client:
И как уже упоминал Аллан (выше), установите UseDefaultCredentials в true.
Использование HttpClient:
var handler = new HttpClientHandler();
handler.UseDefaultCredentials = true;
_httpClient = new HttpClient(handler);
Использование WebClient (ссылка: http://msdn.microsoft.com/en-us/library/system.net.webclient.usedefaultcredentials.aspx)
установить webclient usedefaultcrednetials в 'true'.
С наилучшими пожеланиями!
Ответ 3
Вы уверены, что получаете часть аутентификации? Вы можете использовать fiddler, чтобы проверить, действительно ли выполняются запросы или сервер всегда отвечает с помощью 401 Unauthorized (поскольку вы используете аутентификации).
Вы также можете попытаться реализовать свой собственный AuthorizeAttribute
и поместить в него контрольные точки, чтобы удостовериться, что он попал (вы хотите переопределить метод OnAuthorization
и посмотреть, попадает ли он).
using System.Web.Http;
public class MyAuth : AuthorizeAttribute
{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
base.OnAuthorization(actionContext); //put breakpoint here
}
}
Кроме того, убедитесь, что вы используете атрибут Authorize
от System.Web.Http
, а не от System.Web.Mvc
. См. здесь.
Ответ 4
Вы пытались поместить на свой контроллер атрибут [Authorize]
?
[Authorize]
public class HelloController : ApiController
Ответ 5
Вот ссылка на короткое видео, объясняющее, как использовать авторизацию.
http://www.asp.net/web-api/videos/getting-started/authorization
В сущности, используйте атрибут [Authorize] в классе, поймайте ошибку и верните ответ HTTP 401, а затем попросите клиента обнаружить его и перейти на страницу входа в систему
Ответ 6
Просто добавьте, если вы используете решение tpeczek, а также используете HttpClient, вам может потребоваться сделать это:
var handler = new HttpClientHandler();
handler.UseDefaultCredentials = true;
_httpClient = new HttpClient(handler);
Ответ 7
Похоже на tpeczek ответ, но обновленный, чтобы отразить использование HTTPS. tpeczek ответ не работает для HTTPS, потому что вызов base.OnConfigureBinding(httpBinding);
с HTTPS перезаписывает изменения. Кроме того, вы не можете использовать httpBinding.Security.Mode = HttpBindingSecurityMode.TransportCredentialOnly;
с HTTPS.
Используйте пользовательскую настройку HttpSelfHostConfiguration:
public class NtlmSelfHostConfiguration : HttpSelfHostConfiguration
{
public NtlmSelfHostConfiguration(string baseAddress)
: base(baseAddress)
{ }
public NtlmSelfHostConfiguration(Uri baseAddress)
: base(baseAddress)
{ }
protected override BindingParameterCollection OnConfigureBinding(
HttpBinding httpBinding)
{
if (this.BaseAddress.Scheme == Uri.UriSchemeHttps)
{
var ret = base.OnConfigureBinding(httpBinding);
httpBinding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Ntlm;
return ret;
}
httpBinding.Security.Mode = HttpBindingSecurityMode.TransportCredentialOnly;
httpBinding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Ntlm;
return base.OnConfigureBinding(httpBinding);
}
}
Затем вы можете сделать
var config = new NtlmSelfHostConfiguration("http://myComputerName:8080");
или
var config = new NtlmSelfHostConfiguration("https://myComputerName:8443");
чтобы получить конфигурацию для перехода в new HttpSelfHostServer(config)
Ответ 8
Я немного опаздываю на это. Однако, если вы используете Owin для самостоятельного хостинга и нуждаетесь в окнах auth. В вашем классе запуска вы можете добавить следующее.
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpListener listener = (HttpListener)app.Properties["System.Net.HttpListener"];
listener.AuthenticationSchemes = AuthenticationSchemes.IntegratedWindowsAuthentication;
}
}
Ответ 9
Связанный ответ, для которого он нужен, об основном auth с токеном
Объединяя некоторую помощь, информацию, ответы и собственную систему авторизации, которую я создал для реального веб-API, я мог бы, наконец, использовать теги роли и атрибутов для этого. Выполняется для тега авторизации в заголовке.
Вызов сервера:
var config = new HttpSelfHostConfiguration("http://localhost:8080");
config.UserNamePasswordValidator = new PHVValidator();
config.Routes.MapHttpRoute(
"API Default", "{controller}/{id}",
new { id = RouteParameter.Optional });
using (HttpSelfHostServer server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new DominusForm());
}
Метод Auth: (только для жесткого кодирования, выберите пользователя, пароль и роли из любого места)
public class PHVValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (userName == "admin" && password == "123")
{
string[] rolarray = new string[] { "admin" };
IPrincipal principal = new GenericPrincipal(new GenericIdentity(userName), rolarray);
Thread.CurrentPrincipal = principal;
}
}
}
Метод:
[Authorize(Roles = "admin")]
public HttpResponseMessage Get()
{
do things
}