1

我正在阅读 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在第一次请求时为 null。如果我继续这个休息时间,if 语句会再次被击中,这次headers.Authorization.Scheme是“协商”,而不是“基本”:

在此处输入图像描述

我已经在 WebApiConfig 中注册了我的处理程序:

config.MessageHandlers.Add(new AuthenticationHandler());

但是我不知道为什么 Authorize 属性不尊重基本身份验证,或者为什么 - 因为该方案不是“基本”并且if()我的处理程序返回false- 我应该从我的 API 控制器获取数据得到401 Unauthorized.

我没有在我的 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;
            }
        }

    }
4

3 回答 3

3

当我使用 [Authorize] 装饰 API 中的方法并在上面的 if 语句处设置断点时,headers.Authorization 在第一次请求时为空。

这是意料之中的。这就是它应该如何工作的方式。浏览器仅在收到 401 时才会显示弹出窗口以从用户那里获取凭据。后续请求将具有带有基本方案中凭据的授权标头。

如果我继续这个休息时间,if 语句会再次被击中,这次是 headers.Authorization.Scheme 作为“Negotiate”,而不是“Basic”:

是的,正如 Dominick 所回答的(是 Dominick 吗?),您启用了 Windows 身份验证,这就是您从浏览器获取协商方案的原因。您必须在配置中或使用 IIS 管理器禁用所有身份验证方法。

但是我不知道为什么 Authorize 属性不尊重基本身份验证,或者为什么 - 因为该方案不是“基本”并且我的处理程序中的 if() 返回 false - 我正在从我的 API 控制器获取数据当我应该得到 401 Unauthorized 时。

Authorize 属性对基本身份验证一无所知。它只关心身份是否经过身份验证。由于您启用了匿名身份验证(我猜是这种情况),因此 Authorize 属性很高兴,并且消息处理程序响应处理部分没有 401 来添加 WWW-Authenticate 响应标头,指示 Web API 在基本方案中需要凭据。

于 2013-04-12T07:43:12.853 回答
1

看起来您在 IIS 中为您的应用启用了 Windows 身份验证。禁用配置中的所有身份验证方法(system.web 和 system.webServer)并允许匿名,因为您在消息处理程序中进行了自己的身份验证。

于 2013-04-12T06:53:48.117 回答
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());
}
于 2013-04-12T03:14:51.117 回答