我有一个使用Web API的ASP.NET MVC 4项目。在控制器上,我已使用[Authorize]属性将类设置为需要授权。对于身份验证我使用ASP.NET成员资格提供程序并将我的Web.Config设置为使用“表单”身份验证。这是我被困的地方:
一切都很好,直到我完成测试API并且我想使用[Authorize]属性来保护控制器,这样我就可以开始对我的Membership Provider中的用户进行身份验证。所以我启动Fiddler并进行相同的调用,添加Authorization:Basic属性以及来自我的会员提供商的用户名:密码,如下所示:
我得到的回复是401未授权,在“Auth”下我得到“没有WWW-Authenticate Header存在。”然后我意识到API正在寻找SHA1编码密钥。所以我从搜索中启动一个SHA1生成器并获取我的用户名密码:密码并更新我的请求标头,如下所示:
这也不起作用,我得到相同的结果。此外,我显然需要某种“共享密钥”与服务器一起使用来解码我的用户名/密码。
所以我的问题:
提前致谢!
答案 0 :(得分:68)
您可以将basic authentication与SSL一起使用。在服务器端,我们可以编写一个自定义委托处理程序,它将通过查询我们注册的成员提供程序来验证凭据,如果有效,则检索角色并设置当前主体:
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);
}
}
然后我们在Application_Start
注册此处理程序:
GlobalConfiguration.Configuration.MessageHandlers.Add(
new BasicAuthenticationMessageHandler()
);
现在我们可以使用[Authorize]属性修饰Api控制器,以确保只有经过身份验证的用户才能访问其操作:
[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);
}
}
}
}