我正在遵循Badri L.的 Pro ASP .NET Web API安全性中的第8章,尝试为将由HTTP / JS客户端使用的Web应用程序实现基本身份验证。
我已将以下身份验证处理程序添加到我的WebAPI项目中:
public class AuthenticationHandler : DelegatingHandler
{
private const string SCHEME = "Basic";
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
System.Threading.CancellationToken
cancellationToken)
{
try
{
// Request Processing
var headers = request.Headers;
if (headers.Authorization != null && SCHEME.Equals(headers.Authorization.Scheme))
{
Encoding encoding = Encoding.GetEncoding("iso-8859-1");
// etc
当我使用[Authorize]在我的API中修饰方法并在上面的if
语句中设置断点时,headers.Authorization
在第一次请求时为空。如果我继续这个中断,那么if语句会再次被命中,这次headers.Authorization.Scheme
为“Negotiate”,而不是“Basic”:
我在WebApiConfig中注册了我的处理程序:
config.MessageHandlers.Add(new AuthenticationHandler());
但我不知道为什么Authorize属性不尊重基本身份验证,或者为什么 - 因为该方案不是“基本”而我的处理程序中的if()
返回false
- 当我得到401 Unauthorized
时,我从我的API控制器获取数据。
我的web.config中没有指定任何authenticationType。
知道我做错了什么吗?
编辑:完整处理程序:
public class AuthenticationHandler : DelegatingHandler
{
private const string SCHEME = "Basic";
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
System.Threading.CancellationToken
cancellationToken)
{
try
{
// Request Processing
var headers = request.Headers;
if (headers.Authorization != null && SCHEME.Equals(headers.Authorization.Scheme))
{
Encoding encoding = Encoding.GetEncoding("iso-8859-1");
string credentials = encoding.GetString(Convert.FromBase64String(headers.Authorization.Parameter));
string[] parts = credentials.Split(':');
string userId = parts[0].Trim();
string password = parts[1].Trim();
// TODO: Authentication of userId and Pasword against credentials store here
if (true)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, userId),
new Claim(ClaimTypes.AuthenticationMethod, AuthenticationMethods.Password)
};
var principal = new ClaimsPrincipal(new[] {new ClaimsIdentity(claims, SCHEME)});
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
HttpContext.Current.User = principal;
}
}
var response = await base.SendAsync(request, cancellationToken);
// Response processing
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue(SCHEME));
}
return response;
}
catch (Exception)
{
// Error processing
var response = request.CreateResponse(HttpStatusCode.Unauthorized);
response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue(SCHEME));
return response;
}
}
}
答案 0 :(得分:3)
当我使用[Authorize]在我的API中修饰方法并在上面的if语句中设置断点时,headers.Authorization在第一次请求时为空。
这是预期的。这就是它应该如何工作。浏览器将显示弹出窗口,仅在收到401时才从用户获取凭据。后续请求将具有基本方案中包含凭据的授权标头。
如果我继续这个休息时间,if语句会再次被点击,这次使用headers.Authorization.Scheme作为&#34; Negotiate&#34;,而不是&#34; Basic&#34;:
是的,正如Dominick(是Dominick?)所回答的那样,您启用了Windows身份验证,这就是您从浏览器中获取协商方案的原因。您必须在配置中或使用IIS管理器禁用所有身份验证方法。
但我不知道为什么Authorize属性不尊重基本身份验证,或者为什么 - 因为该方案不是&#34; basic&#34;并且我的处理程序中的if()返回false - 当我应该获得401 Unauthorized时,我从API控制器获取数据。
授权属性对基本身份验证一无所知。所有它关心的是身份是否经过身份验证。由于您启用了匿名身份验证(我猜是这种情况),Authorize属性很高兴,并且消息处理程序响应处理部分没有401添加WWW-Authenticate响应头,指示Web API需要Basic方案中的凭据。
答案 1 :(得分:1)
您似乎已在IIS中为您的应用启用了Windows身份验证。禁用config(system.web和system.webServer)中的所有身份验证方法,并允许匿名,因为您在消息处理程序中执行自己的身份验证。
答案 2 :(得分:0)
我认为你需要在global.asa上注册处理程序
这篇文章看起来不错:http://byterot.blogspot.com.br/2012/05/aspnet-web-api-series-messagehandler.html
你的global.asa.cs将会是这样的:
public static void Application_Start(GlobalFilterCollection filters) {
//...
GlobalConfiguration.Configuration.MessageHandlers.Add(new AuthenticationHandler());
}