Asp.net mvc 具有成员资格提供程序的ASP.NET MVC 4 Web API身份验证

Asp.net mvc 具有成员资格提供程序的ASP.NET MVC 4 Web API身份验证,asp.net-mvc,asp.net-membership,forms-authentication,asp.net-web-api,fiddler,Asp.net Mvc,Asp.net Membership,Forms Authentication,Asp.net Web Api,Fiddler,我有一个使用Web API的ASP.NET MVC 4项目。在控制器上,我使用[Authorize]属性将类设置为需要授权。对于身份验证,我使用ASP.NET成员资格提供程序,并将我的Web.Config设置为使用“表单”身份验证。这就是我被困的地方: 在我完成API测试之前,一切都很顺利,我想用[Authorize]属性保护控制器,这样我就可以开始在我的会员资格提供商中测试针对用户的身份验证。因此,我启动Fiddler并进行相同的调用,添加Authorization:Basic属性以及来自我的

我有一个使用Web API的ASP.NET MVC 4项目。在控制器上,我使用[Authorize]属性将类设置为需要授权。对于身份验证,我使用ASP.NET成员资格提供程序,并将我的Web.Config设置为使用“表单”身份验证。这就是我被困的地方:

在我完成API测试之前,一切都很顺利,我想用[Authorize]属性保护控制器,这样我就可以开始在我的会员资格提供商中测试针对用户的身份验证。因此,我启动Fiddler并进行相同的调用,添加Authorization:Basic属性以及来自我的会员资格提供商的username:password,如下所示:

我得到的响应是401 unauthorized,在“Auth”下我得到“No WWW Authenticate Header is present”。然后我意识到API正在寻找一个SHA1编码的密钥。因此,我从搜索中启动了一个SHA1生成器,并获得用户名:密码的哈希值,然后更新我的请求头,如下所示:

这也不起作用,我得到了相同的结果。此外,我显然需要某种“共享密钥”与服务器一起使用,以解码我的用户名/密码

所以我的问题是:

  • 如何从服务器获取此密钥(或者在本例中是运行VS 2012的虚拟IIS)
  • 如何使用此选项在Fiddler中使用来自ASP.NET成员资格提供程序的用户名/密码进行身份验证调用
  • 我将如何在客户端应用程序中使用它来进行相同的调用(C#WPF应用程序)
  • 在我的HTTP调用中与SSL结合使用时,这是最佳实践吗?如果不是,是什么
  • 提前谢谢

    您可以使用SSL。在服务器端,我们可以编写一个自定义委托处理程序,通过查询我们注册的memebership提供程序来验证凭据,如果有效,则检索角色并设置当前主体:

    public class BasicAuthenticationMessageHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var authHeader = request.Headers.Authorization;
    
            if (authHeader == null)
            {
                return base.SendAsync(request, cancellationToken);
            }
    
            if (authHeader.Scheme != "Basic")
            {
                return base.SendAsync(request, cancellationToken);
            }
    
            var encodedUserPass = authHeader.Parameter.Trim();
            var userPass = Encoding.ASCII.GetString(Convert.FromBase64String(encodedUserPass));
            var parts = userPass.Split(":".ToCharArray());
            var username = parts[0];
            var password = parts[1];
    
            if (!Membership.ValidateUser(username, password))
            {
                return base.SendAsync(request, cancellationToken);
            }
    
            var identity = new GenericIdentity(username, "Basic");
            string[] roles = Roles.Provider.GetRolesForUser(username);
            var principal = new GenericPrincipal(identity, roles);
            Thread.CurrentPrincipal = principal;
            if (HttpContext.Current != null)
            {
                HttpContext.Current.User = principal;
            }
    
            return base.SendAsync(request, cancellationToken);
        }
    }
    
    现在我们可以有一个Api控制器,它将被修饰为[Authorize]属性,以确保只有经过身份验证的用户才能访问其操作:

    [Authorize]
    public class ValuesController : ApiController
    {
        public string Get()
        {
            return string.Format("Hello {0}", User.Identity.Name);
        }
    }
    
    好的,现在我们来看一个示例客户机:

    using System;
    using System.Net;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Text;
    
    class Program
    {
        static void Main()
        {
            // since for testing purposes I am using IIS Express
            // with an invalid SSL certificate I need to desactivate
            // the check for this certificate.
            ServicePointManager.ServerCertificateValidationCallback += 
                (sender, certificate, chain, sslPolicyErrors) => true;
    
            using (var client = new HttpClient())
            {
                var buffer = Encoding.ASCII.GetBytes("john:secret");
                var authHeader = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(buffer));
                client.DefaultRequestHeaders.Authorization = authHeader;
                var task = client.GetAsync("https://localhost:44300/api/values");
                if (task.Result.StatusCode == HttpStatusCode.Unauthorized)
                {
                    Console.WriteLine("wrong credentials");
                }
                else
                {
                    task.Result.EnsureSuccessStatusCode();
                    Console.WriteLine(task.Result.Content.ReadAsAsync<string>().Result);
                }
            }
        }
    }
    
    使用系统;
    Net系统;
    使用System.Net.Http;
    使用System.Net.Http.Header;
    使用系统文本;
    班级计划
    {
    静态void Main()
    {
    //因为出于测试目的,我正在使用IIS Express
    //由于SSL证书无效,我需要取消激活
    //此证书的支票。
    ServicePointManager.ServerCertificateValidationCallback+=
    (发送方、证书、链、sslPolicyErrors)=>true;
    使用(var client=new HttpClient())
    {
    var buffer=Encoding.ASCII.GetBytes(“john:secret”);
    var authHeader=新的AuthenticationHeaderValue(“基本”,Convert.ToBase64String(缓冲区));
    client.DefaultRequestHeaders.Authorization=authHeader;
    var task=client.GetAsync(“https://localhost:44300/api/values");
    if(task.Result.StatusCode==HttpStatusCode.Unauthorized)
    {
    Console.WriteLine(“错误凭证”);
    }
    其他的
    {
    task.Result.EnsureSuccessStatusCode();
    Console.WriteLine(task.Result.Content.ReadAsAsync().Result);
    }
    }
    }
    }
    
    谢谢Darin,这正是我需要的<控制器方法中的code>User.Identity.Name对我而言为空,
    User.Identity.IsAuthenticated
    false
    。我可以在调试器中看到,
    Thread.CurrentPrincipal
    被设置为消息处理程序中具有正确用户名和角色的主体。另外,
    [Authorization(Roles=…)]
    属性也得到了尊重:如果我使用了角色错误的用户,我会得到未经授权的响应,并且不会到达控制器方法。但是
    User.Identity
    没有我在消息处理程序中设置的值。“你知道会出什么问题吗?”斯劳玛,我无法复制这个。也许你可以开始一个新的线程,一步一步地解释如何重现这个问题(当然是从一个空的项目开始)。我无法在一个新的项目中重现它。但同时我发现,
    User
    主体在ApiController构造函数中是正确的,但在controller方法中是错误的。中间是一个自定义MediaTypeFormatter。通过设置一些断点,我看到调用链是:ApiController构造函数->MediaTypeFormatter->ApiController方法。在格式化程序中,主体会被覆盖,尽管我没有使用任何与安全性相关的东西。如果我在global.asax中注释掉格式化程序注册,则主体保持正确。我需要继续调试…您好,方法:“Membership.ValidateUser()”返回false。我假设我需要设置成员身份默认数据库连接?如果是,我在哪里做?
    using System;
    using System.Net;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Text;
    
    class Program
    {
        static void Main()
        {
            // since for testing purposes I am using IIS Express
            // with an invalid SSL certificate I need to desactivate
            // the check for this certificate.
            ServicePointManager.ServerCertificateValidationCallback += 
                (sender, certificate, chain, sslPolicyErrors) => true;
    
            using (var client = new HttpClient())
            {
                var buffer = Encoding.ASCII.GetBytes("john:secret");
                var authHeader = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(buffer));
                client.DefaultRequestHeaders.Authorization = authHeader;
                var task = client.GetAsync("https://localhost:44300/api/values");
                if (task.Result.StatusCode == HttpStatusCode.Unauthorized)
                {
                    Console.WriteLine("wrong credentials");
                }
                else
                {
                    task.Result.EnsureSuccessStatusCode();
                    Console.WriteLine(task.Result.Content.ReadAsAsync<string>().Result);
                }
            }
        }
    }