我遇到的情况是我在其他文章中找不到的。我正在设计一个由移动应用程序使用的RESTful服务器。在这种情况下,用户名和密码是应用程序调用中标题的一部分,没有登录屏幕。
以下代码用于验证用户信息,控制器具有安全控制功能。
我的问题是:如何在ApiController控制器中填充iPrincipal?
我创建了一个在WebApiConfig.cs
处理的过滤器public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Filtro de login
config.Filters.Add(new tbAuthorize());
tbAuthorize的代码是:
public class tbAuthorize : AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext actionContext)
{
string username;
string password;
if (GetUserNameAndPassword(actionContext, out username, out password))
{
if (!isUserAuthorized(username, password))
return false;
else
{
//Users = username;
return true;
}
}
else
return false;
}
private bool GetUserNameAndPassword(HttpActionContext actionContext, out string username, out string password)
{
username = "";
password = "";
if (actionContext.Request.Headers.Authorization == null) return false;
// Convert 64 code to separated string[]
string[] s = ParseAuthHeader(actionContext.Request.Headers.Authorization.ToString());
if (s == null)
return false;
username = s[0];
password = s[1];
return true;
}
private string[] ParseAuthHeader(string authHeader)
{
// Check this is a Basic Auth header
if (authHeader == null || authHeader.Length == 0 || !authHeader.StartsWith("Basic")) return null;
// Pull out the Credentials with are seperated by ':' and Base64 encoded
string base64Credentials = authHeader.Substring(6);
string[] credentials = Encoding.ASCII.GetString(Convert.FromBase64String(base64Credentials)).Split(new char[] { ':' });
if (credentials.Length != 2 || string.IsNullOrEmpty(credentials[0]) || string.IsNullOrEmpty(credentials[0])) return null;
// Okay this is the credentials
return credentials;
}
private bool isUserAuthorized(string username, string password)
{
// Valid the user at database
var userId = new UsersController().Login(username, password);
// Membership.GetUser() is null
//Users = Membership.GetUser().Email;
return userId != 0;
}
}
问题是我无法访问Response中的cookie,而且我没有找到填充iPrincipal的方法。
我需要在this.User.Identity.Name中包含数据,如下所示:
[tbAuthorize]
public class UsersController : ApiController
{
public void test()
{
string x = this.User.Identity.Name;
}
感谢您的帮助,
Marco Castro
答案 0 :(得分:1)
身份验证和授权是两个不同的事情。在授权用户之前,您必须对其进行身份验证。
使用WebApi
,您拥有Delegatinghandler
的管道概念。消息从一个处理程序转到下一个处理程序,直到发送响应。我建议您创建一个DelegatingHandler
来验证用户身份。然后,您可以使用AuthorizeAttribute
来阻止未经身份验证的用户访问您的API。
以下是使用HTTP Basic
验证用户身份的示例public abstract class BasicAuthMessageHandler : DelegatingHandler
{
private const string BasicAuthResponseHeader = "WWW-Authenticate";
private const string BasicAuthResponseHeaderValue = "Basic Realm=\"{0}\"";
protected BasicAuthMessageHandler()
{
}
protected BasicAuthMessageHandler(HttpConfiguration httpConfiguration)
{
InnerHandler = new HttpControllerDispatcher(httpConfiguration);
}
protected virtual string GetRealm(HttpRequestMessage message)
{
return message.RequestUri.Host;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
// Process request
AuthenticationHeaderValue authValue = request.Headers.Authorization;
if (authValue != null && !String.IsNullOrWhiteSpace(authValue.Parameter) &&
string.Equals(authValue.Scheme, "basic", StringComparison.OrdinalIgnoreCase))
{
// Try to authenticate user
IPrincipal principal = ValidateHeader(authValue.Parameter);
if (principal != null)
{
request.GetRequestContext().Principal = principal;
}
}
return base.SendAsync(request, cancellationToken) // Send message to the InnerHandler
.ContinueWith(task =>
{
// Process response
var response = task.Result;
if (response.StatusCode == HttpStatusCode.Unauthorized &&
!response.Headers.Contains(BasicAuthResponseHeader))
{
response.Headers.Add(BasicAuthResponseHeader,
string.Format(BasicAuthResponseHeaderValue, GetRealm(request)));
}
return response;
}, cancellationToken);
}
private IPrincipal ValidateHeader(string authHeader)
{
// Decode the authentication header & split it
var fromBase64String = Convert.FromBase64String(authHeader);
var lp = Encoding.Default.GetString(fromBase64String);
if (string.IsNullOrWhiteSpace(lp))
return null;
string login;
string password;
int pos = lp.IndexOf(':');
if (pos < 0)
{
login = lp;
password = string.Empty;
}
else
{
login = lp.Substring(0, pos).Trim();
password = lp.Substring(pos + 1).Trim();
}
return ValidateUser(login, password);
}
protected abstract IPrincipal ValidateUser(string userName, string password);
}
编写自己的用户验证逻辑。例如:
public class SampleBasicAuthMessageHandler : BasicAuthMessageHandler
{
protected override IPrincipal ValidateUser(string userName, string password)
{
if (string.Equals(userName, "Meziantou", StringComparison.OrdinalIgnoreCase) && password == "123456")
return new GenericPrincipal(new GenericIdentity(userName, "Basic"), new string[0]);
return null;
}
}
最后,您必须注册Handler
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.MessageHandlers.Add(new SampleBasicAuthMessageHandler());
您将在Github上找到一个完整的示例:https://github.com/meziantou/Samples/tree/master/Web%20Api%20-%20Basic%20Authentication