如何分辨[授权]属性使用基本身份验证与自定义消息处理程序? [英] How to tell [Authorize] attribute to use Basic authentication with custom message handler?

查看:265
本文介绍了如何分辨[授权]属性使用基本身份验证与自定义消息处理程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我沿着第八章下面的临ASP .NET的Web API安全性的由巴德里L.,试图实施,将通过HTTP / JS客户端使用的Web应用程序基本身份验证。

我添加以下验证处理程序来我的WebAPI项目:

 公共类的AuthenticationHandler:DelegatingHandler
    {
        私人常量字符串格式=基本;
        保护异步覆盖任务其中p型Htt presponseMessage> SendAsync(HTT prequestMessage要求,
                                                                               System.Threading.CancellationToken
                                                                                   的CancellationToken)
        {
            尝试
            {
                //请求处理
                VAR头= request.Headers;
                如果(headers.Authorization = NULL&放大器;!&安培; SCHEME.Equals(headers.Authorization.Scheme))
                {
                    编码编码= Encoding.GetEncoding(ISO-8859-1);
                    //等

当我在装点我的[授权] API方法,并在如果语句设置断点以上, headers.Authorization 是在第一个请求无效。如果我继续在这休息,if语句被再次袭来,这次 headers.Authorization.Scheme 为协商,而不是基本:

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

  config.MessageHandlers.Add(新的AuthenticationHandler());

但我不知所措,为什么授权属性是不尊重基本身份验证,或者为什么 - 因为该方案是不是基本和如果()在我的处理程序返回 - 我从我的API控制器获取数据时,我应该得到 401未授权

我没有指定在我的web.config任何authenticationType。

任何想法,我做错了什么?

编辑:全处理程序:

 公共类的AuthenticationHandler:DelegatingHandler
    {
        私人常量字符串格式=基本;
        保护异步覆盖任务其中p型Htt presponseMessage> SendAsync(HTT prequestMessage要求,
                                                                               System.Threading.CancellationToken
                                                                                   的CancellationToken)
        {
            尝试
            {
                //请求处理
                VAR头= request.Headers;
                如果(headers.Authorization = NULL&放大器;!&安培; SCHEME.Equals(headers.Authorization.Scheme))
                {
                    编码编码= Encoding.GetEncoding(ISO-8859-1);
                    字符串凭证= encoding.GetString(Convert.FromBase64String(headers.Authorization.Parameter));
                    字符串[] =零件credentials.Split(':');
                    字符串userid =零件[0] .Trim();
                    字符串密码=部分[1] .Trim();
                    // TODO:帐户及Pasword的认证证书对存储在这里
                    如果属实)
                    {
                        VAR索赔=新的List<权利要求GT;
                            {
                                新的索赔(ClaimTypes.Name,用户id)
                                新的索赔(ClaimTypes.AuthenticationMethod,AuthenticationMethods.Password)
                            };
                        VAR本金=新ClaimsPrincipal(新[] {新ClaimsIdentity(索赔,方案)});
                        = Thread.CurrentPrincipal中校长;
                        如果(HttpContext.Current!= NULL)
                            HttpContext.Current.User =本金;
                    }                }                VAR响应=等待base.SendAsync(请求的CancellationToken);
                //响应处理
                如果(response.Status code ==的HTTPStatus code.Unauthorized)
                {
                    response.Headers.WwwAuthenticate.Add(新AuthenticationHeaderValue(方案));
                }
                返回响应;
            }
            赶上(例外)
            {
                //错误处理
                VAR响应= request.CreateResponse(的HTTPStatus code.Unauthorized);
                response.Headers.WwwAuthenticate.Add(新AuthenticationHeaderValue(方案));
                返回响应;
            }
        }    }


解决方案

  

当我在装点我的[授权] API方法和设置在上面的if语句断点,headers.Authorization是在第一个请求无效。


这是预期。这是它是如何工作的。浏览器会显示弹出来获得用户凭据只有在接收到一个401后续请求将与在基本方案凭证授权头。


  

如果我继续在这休息,if语句被再次袭来,这一次headers.Authorization.Scheme为协商,而不是基本:


是的,作为多米尼克回答(是多米尼克?),你必须启用Windows身份验证,这是对您是否获得了协商方案从浏览器的后退的原因。您必须使用IIS管理器禁用无论是在配置还是所有身份验证方法。


  

不过,我在茫然,我为什么授权属性是不尊重基本身份验证,或者为什么 - 因为该方案是不是基本,而如果()在我的处理程序返回假的 - 从我得到的数据当我应该得到我的API控制器401未授权。


授权属性一无所知基本身份验证。所有它关心是如果身份被认证或没有。既然您已经启用匿名身份验证(我猜是这样),授权属性是快乐的,没有401的消息处理程序响应处理部分添加WWW身份验证响应头表示网络API预计将在基本计划凭据。

I'm following along Chapter 8 in Pro ASP .NET Web API Security by Badri L., trying to implement basic authentication for a web application that will be consumed by HTTP/JS clients.

I've added the following Authentication Handler to my WebAPI project:

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

When I decorate methods in my API with [Authorize] and set a breakpoint at the if statement above, headers.Authorization is null upon the first request. If I continue on this break, the if statement gets hit again, this time with headers.Authorization.Scheme as "Negotiate", instead of "Basic":

I have registered my Handler in WebApiConfig:

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

But I'm at a loss as to why the Authorize attribute is not respecting basic authentication, or why - since the scheme is not "basic" and the if() in my handler returns false - I'm getting data from my API controller when I should be getting 401 Unauthorized.

I have not specified any authenticationType in my web.config.

Any idea what I'm doing wrong?

Edit: Full Handler:

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;
            }
        }

    }

解决方案

When I decorate methods in my API with [Authorize] and set a breakpoint at the if statement above, headers.Authorization is null upon the first request.

This is expected. This is how it is supposed to work. Browser will show the popup to get credentials from the user only when it receives a 401. Subsequent request will have the authorization header with credentials in the basic scheme.

If I continue on this break, the if statement gets hit again, this time with headers.Authorization.Scheme as "Negotiate", instead of "Basic":

Yes, as answered by Dominick (is it Dominick?), you have Windows Authentication enabled and that is the reason for you getting the Negotiate scheme back from the browser. You must disable all authentication methods either in the config or using IIS manager.

But I'm at a loss as to why the Authorize attribute is not respecting basic authentication, or why - since the scheme is not "basic" and the if() in my handler returns false - I'm getting data from my API controller when I should be getting 401 Unauthorized.

Authorize attribute knows nothing about basic authentication. All it cares is if the identity is authenticated or not. Since you have anonymous authentication enabled (I guess that is the case), Authorize attribute is happy and there is no 401 for the message handler response handling part to add the WWW-Authenticate response header indicating that web API expects credentials in the Basic scheme.

这篇关于如何分辨[授权]属性使用基本身份验证与自定义消息处理程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆