【问题标题】:How to create custom iPrincipal in MVC 4, WinAPI如何在 MVC 4、WinAPI 中创建自定义 iPrincipal
【发布时间】:2014-05-03 02:01:17
【问题描述】:

我遇到了在其他文章中找不到的情况。我正在设计一个 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;
    }

感谢您的帮助,

马可·卡斯特罗

【问题讨论】:

    标签: asp.net-mvc iprincipal


    【解决方案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

    【讨论】:

      猜你喜欢
      • 2011-08-14
      • 1970-01-01
      • 2010-12-25
      • 2010-11-07
      • 1970-01-01
      • 2014-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多