【问题标题】:Enable Basic Authentication for Azure App Service WebApi OWIN为 Azure 应用服务 WebApi OWIN 启用基本身份验证
【发布时间】:2015-11-27 13:27:54
【问题描述】:

我有一个 ASP.Net 4.5.2 MVC5 WebApi 5.2.3 应用程序,它通常通过 OWIN 管道使用 OAuth/Jwt 安全性。现在,我有一个外部服务网络挂钩,它通过 POST 调用我的一个 WebApi 控制器。此 webhook 服务仅支持基于 Https 的基本身份验证。这很好,如果我只能让我的过滤器(或其他东西)工作。

我的过滤器基于一个不错的 example by Rick Strahl 但是,当我添加这个类,然后在我的 ApiController 操作上方添加我的 [MyBasicAuthFilter] 时,我得到的只是一个服务器错误 500 消息,其中包含 {"Message":"An error has发生了。”}。

当我从 POST 调用中删除“授权:基本 dXNlcasdfasfdsfasd=”标头时,代码将进入我的新过滤器。太棒了 :-[。因此,管道中较早的部分不喜欢此标头存在的事实。我在阅读了一下之后怀疑 IIS 设置。但是在尝试通过我的 Web.Config 强制 Azure App Service IIS 并立即阻止对我的站点的所有访问之后,我想我会来这里寻求一些提示。

想法/提示?

【问题讨论】:

    标签: asp.net-web-api azure-web-app-service iis-8 basic-authentication


    【解决方案1】:

    好的,这里是这里发生的事情的独家新闻。现有的 JsonWebTokenValidationHandler (Message Handler) 只是在标头中寻找“Bearer”令牌。如果出现任何其他令牌,则将其标记为潜在攻击并返回 HttpStatus 500。如果标头中根本没有令牌,则它将返回挑战 HttpStatus 401。无论如何,对于我的简约 BasicAuth 要求的最佳解决方案(在 JWT 令牌之上)是我的 JsonWebTokenValidationHandler.cs 的以下(完整)内容。这现在可以处理 Bearer (JWT) 令牌和基本身份验证令牌。欢迎评论。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Web;
    
    public class JsonWebTokenValidationHandler : DelegatingHandler
    {
        public string SymmetricKey { get; set; } // A0 client secret
    
        public string Audience { get; set; } // A0 client ID
    
        public string Issuer { get; set; } // A0 our A0 domain
    
        private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
        {
            token = null;
            IEnumerable<string> authzHeaders;
    
            if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1)
            {
                // Fail if no Authorization header or more than one Authorization headers  
                // are found in the HTTP request  
                return false;
            }
    
            // Remove the bearer token scheme prefix and return the rest as ACS token  
            var bearerToken = authzHeaders.ElementAt(0);
            token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
    
            return true;
        }
    
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            string token;
            HttpResponseMessage errorResponse = null;
    
            if (TryRetrieveToken(request, out token))
            {
                try
                {
                    // ++
                    // Added BasicAuth to our JWT Auth
                    // If it is a BasicAuth token, then check it first and bypass JWT validation
                    // See Asp.Net WebApi security book for infos on this.
                    //
                    if (token.Contains("Basic"))
                    {
                        var authHeader = Encoding.Default.GetString(Convert.FromBase64String(token.Substring(6)));
    
                        // find first : as password allows for :
                        int idx = authHeader.IndexOf(':');
                        if (idx < 0)
                            return null;
    
                        string username = authHeader.Substring(0, idx);
                        string password = authHeader.Substring(idx + 1);
    
                        // Check the user's validity and reuse the JWT challenge 401 exception if not valid.
                        if (!ValidateBasicAuthUser(username, password))
                        {
                            throw new JsonWebToken.TokenValidationException(
                                $"Username or password missmatch for username: {username}");
                        }
    
                        // If OK, then let them in and continue
                        var identity = new BasicAuthenticationIdentity(username, password);
                        var principal = new GenericPrincipal(identity, null);
    
                        Thread.CurrentPrincipal = principal;
                        if (HttpContext.Current != null)
                        {
                            HttpContext.Current.User = Thread.CurrentPrincipal;
                        }
                    }
                    else
                    {
                        // --
    
                        // Handle JWT Tokens here or return server error 500 if it is not a valid token.
                        var secret = this.SymmetricKey.Replace('-', '+').Replace('_', '/');
    
                        Thread.CurrentPrincipal = JsonWebToken.ValidateToken(
                            token,
                            secret,
                            audience: this.Audience,
                            checkExpiration: true,
                            issuer: this.Issuer);
    
                        if (HttpContext.Current != null)
                        {
                            HttpContext.Current.User = Thread.CurrentPrincipal;
                        }
                    }
                }
                catch (JWT.SignatureVerificationException ex)
                {
                    errorResponse = request.CreateErrorResponse(HttpStatusCode.Unauthorized, ex);
                }
                catch (JsonWebToken.TokenValidationException ex)
                {
                    errorResponse = request.CreateErrorResponse(HttpStatusCode.Unauthorized, ex);
                }
                catch (Exception ex)
                {
                    errorResponse = request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
                }
            }
    
            return errorResponse != null ?
                Task.FromResult(errorResponse) :
                base.SendAsync(request, cancellationToken);
        }
    
        /// <summary>
        /// rht: Check our BasicAuth passwords e.g. from Cb WebHook
        /// Usage: http://weblog.west-wind.com/posts/2013/Apr/18/A-WebAPI-Basic-Authentication-Authorization-Filter
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        private bool ValidateBasicAuthUser(string username, string password)
        {
            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
                return false;
    
            var ok = false;
            //
            // Our valid usernames and passwords
            //
            switch (username)
            {
                case "your user 1 here":
                    {
                        if (password == "your password here") ok = true;
                    }
                    break;
                case "your user 2 here or from DB, whatever":
                    {
                        if (password == "pwd") ok = true;
                    }
                    break;
            }
    
            return ok;
        }
    } // cl
    
    //
    // See: http://weblog.west-wind.com/posts/2013/Apr/18/A-WebAPI-Basic-Authentication-Authorization-Filter
    // And Asp.Net WebApi Security book.
    public class BasicAuthenticationIdentity : GenericIdentity
    {
        public BasicAuthenticationIdentity(string name, string password)
            : base(name, "Basic")
        {
            this.Password = password;
        }
    
        /// <summary>
        /// Basic Auth Password for custom authentication
        /// </summary>
        public string Password { get; set; }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-15
      • 2019-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-14
      • 2021-01-26
      • 1970-01-01
      相关资源
      最近更新 更多