3

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

谢谢你的帮助,

马可·卡斯特罗

4

1 回答 1

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

于 2014-05-03T10:45:35.507 回答