C# 如何告诉[Authorize]属性使用自定义消息处理程序的基本身份验证?

C# 如何告诉[Authorize]属性使用自定义消息处理程序的基本身份验证?,c#,asp.net-mvc,security,asp.net-web-api,authorization,C#,Asp.net Mvc,Security,Asp.net Web Api,Authorization,我将遵循Badri L.在ProASP.NETWebAPI安全中的第8章,尝试为HTTP/JS客户端使用的Web应用程序实现基本身份验证 我已将以下身份验证处理程序添加到我的WebAPI项目中: public class AuthenticationHandler : DelegatingHandler { private const string SCHEME = "Basic"; protected async override Task<Htt

我将遵循Badri L.在ProASP.NETWebAPI安全中的第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属性不尊重基本身份验证,或者为什么-因为方案不是“基本”的,并且我的处理程序中的
if()
返回
false
-我从API控制器获取数据,而我应该获取
401未经授权的

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

    }
公共类AuthenticationHandler:DelegatingHandler
{
private const string SCHEME=“Basic”;
受保护的异步重写任务SendAsync(HttpRequestMessage请求,
System.Threading.CancellationToken
取消令牌)
{
尝试
{
//请求处理
var headers=request.headers;
if(headers.Authorization!=null&&SCHEME.Equals(headers.Authorization.SCHEME))
{
Encoding Encoding=Encoding.GetEncoding(“iso-8859-1”);
字符串凭据=encoding.GetString(Convert.FromBase64String(headers.Authorization.Parameter));
string[]parts=credentials.Split(“:”);
字符串userId=parts[0]。Trim();
字符串密码=零件[1]。修剪();
//TODO:根据此处的凭据存储对用户ID和Pasword进行身份验证
如果(真)
{
var索赔=新列表
{
新索赔(ClaimTypes.Name、userId),
新声明(ClaimTypes.AuthenticationMethod、AuthenticationMethods.Password)
};
var principal=新索赔(新[]{新索赔实体(索赔、方案)});
Thread.CurrentPrincipal=主体;
if(HttpContext.Current!=null)
HttpContext.Current.User=主体;
}
}
var response=await base.sendaync(请求、取消令牌);
//响应处理
if(response.StatusCode==HttpStatusCode.Unauthorized)
{
添加(新的AuthenticationHeaderValue(SCHEME));
}
返回响应;
}
捕获(例外)
{
//错误处理
var response=request.CreateResponse(HttpStatusCode.Unauthorized);
添加(新的AuthenticationHeaderValue(SCHEME));
返回响应;
}
}
}

我认为您需要在global.asa上注册处理程序

这篇文章看起来不错:

您的global.asa.cs将具有以下内容:

public static void Application_Start(GlobalFilterCollection filters) {
   //...
   GlobalConfiguration.Configuration.MessageHandlers.Add(new AuthenticationHandler());
}

我认为您需要在global.asa上注册处理程序

这篇文章看起来不错:

您的global.asa.cs将具有以下内容:

public static void Application_Start(GlobalFilterCollection filters) {
   //...
   GlobalConfiguration.Configuration.MessageHandlers.Add(new AuthenticationHandler());
}

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

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

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

这是意料之中的。这就是它的工作原理。浏览器将显示弹出窗口,以便仅在收到401时从用户处获取凭据。后续请求将在基本方案中具有带有凭据的授权标头

如果我继续此中断,If语句将再次被命中,这次将headers.Authorization.Scheme设置为“协商”,而不是“基本”:

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

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

Authorize属性对基本身份验证一无所知。它关心的只是身份是否经过身份验证。由于您启用了匿名身份验证(我猜是这样),Authorize属性很好,消息处理程序响应处理部分没有401来添加WWW Authenticate响应头,这表明web API需要基本方案中的凭据

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

这是意料之中的。这就是它的工作原理。浏览器将显示弹出窗口,以便仅在收到401时从用户处获取凭据。后续请求将在基本方案中具有带有凭据的授权标头

如果我继续休息,如果