如何在MVC 4,WinAPI中创建自定义iPrincipal

时间:2014-05-03 02:01:18

标签: asp.net-mvc iprincipal

我遇到的情况是我在其他文章中找不到的。我正在设计一个由移动应用程序使用的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

1 个答案:

答案 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