ASP。NET MVC 4 Web API认证和会员提供程序。

时间:2022-11-07 03:15:10

I have an ASP.NET MVC 4 Project using the Web API. On the controller I have set the class to require authorization using the [Authorize] attribute. For Authentication I am using the ASP.NET Membership Provider and have my Web.Config set to use "Forms" Authentication. Here is where I am stuck:

我有一个ASP。NET MVC 4项目使用Web API。在控制器上,我使用[Authorize]属性设置了需要授权的类。对于身份验证,我使用的是ASP。拥有我的网络会员。配置设置为使用“表单”身份验证。这就是我被困住的地方:

Everything is working great up until the point that I am done with testing the API and I want to secure the controller with the [Authorize] attribute so I can start testing authentication against users in my Membership Provider. So I fire up Fiddler and make the same call adding the Authorization:Basic attribute along with a username:password from my membership provider like so:

在我完成对API的测试之前,一切都运行得很好,我想用[Authorize]属性保护控制器,这样我就可以开始对我的成员资格提供程序中的用户进行身份验证。于是我启动了Fiddler,并进行了相同的调用,添加了授权:Basic属性以及来自我的会员提供者的用户名:密码如下:

ASP。NET MVC 4 Web API认证和会员提供程序。

The response I get is 401 unauthorized and under "Auth" I get "No WWW-Authenticate Header is present." Then I realize that the API is looking for an SHA1 encoded key. So I fire up an SHA1 generator from a search and get a hash for my username:password and update my Request Header like so:

我得到的响应是401未经授权,在“Auth”下我得到的“没有WWW-Authenticate头存在”。然后我意识到API正在寻找一个SHA1编码密钥。因此,我从搜索中启动SHA1生成器,获取我的用户名:密码的散列,并更新我的请求头,如下所示:

ASP。NET MVC 4 Web API认证和会员提供程序。

This does not work either and I get the same results. Also I obviously need some sort of "shared secret key" to use with the server to decode my username/password.

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

So my questions:

所以我的问题:

  1. How do I get this key from the server (or in this case Virtual IIS running off VS 2012).
  2. 如何从服务器(在本例中,虚拟IIS运行VS 2012)获得此密钥。
  3. How do I use this to make Authenticated calls in Fiddler using usernames/passwords from an ASP.NET Membership Provider.
  4. 我如何使用它在Fiddler中使用来自ASP的用户名/密码进行验证调用。网会员提供者。
  5. How will I use this in my client application to make the same calls (C# WPF App).
  6. 我将如何在我的客户端应用程序中使用它来进行相同的调用(c# WPF应用程序)。
  7. Is this best practive when combined with SSL on my HTTP calls? If not what is?
  8. 在我的HTTP调用中与SSL结合时,这是最佳实践吗?如果不是是什么?

Thanks in advance!

提前谢谢!

1 个解决方案

#1


67  

You could use basic authentication with SSL. On the server side we could write a custom delegating handler which will verify the credentials by querying the memebership provider that we registered, and if valid, retrieve the roles and set the current principal:

可以使用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);
    }
}

We then register this handler in Application_Start:

然后我们在Application_Start中注册这个处理程序:

GlobalConfiguration.Configuration.MessageHandlers.Add(
    new BasicAuthenticationMessageHandler()
);

Now we could have an Api controller that will be decorated with the [Authorize] attribute to ensure that only authenticated users can access its actions:

现在我们可以有一个Api控制器,它将用[授权]属性来修饰,以确保只有经过身份验证的用户才能访问它的操作:

[Authorize]
public class ValuesController : ApiController
{
    public string Get()
    {
        return string.Format("Hello {0}", User.Identity.Name);
    }
}

Alright, now let's look at a sample client:

好了,现在我们来看一个样本客户端:

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

#1


67  

You could use basic authentication with SSL. On the server side we could write a custom delegating handler which will verify the credentials by querying the memebership provider that we registered, and if valid, retrieve the roles and set the current principal:

可以使用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);
    }
}

We then register this handler in Application_Start:

然后我们在Application_Start中注册这个处理程序:

GlobalConfiguration.Configuration.MessageHandlers.Add(
    new BasicAuthenticationMessageHandler()
);

Now we could have an Api controller that will be decorated with the [Authorize] attribute to ensure that only authenticated users can access its actions:

现在我们可以有一个Api控制器,它将用[授权]属性来修饰,以确保只有经过身份验证的用户才能访问它的操作:

[Authorize]
public class ValuesController : ApiController
{
    public string Get()
    {
        return string.Format("Hello {0}", User.Identity.Name);
    }
}

Alright, now let's look at a sample client:

好了,现在我们来看一个样本客户端:

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