asp mvc 3 ActionFilter for basic authentication

£可爱£侵袭症+ 提交于 2019-11-29 15:08:46

问题


I have an ASP MVC3 restful service that uses basic authentication. After searching stack overflow, I created the following code.

public class BasicAuthentication : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var req = filterContext.HttpContext.Request;
        if (String.IsNullOrEmpty(req.Headers["Authorization"]))
        {
            filterContext.Result = new HttpNotFoundResult();
        }
        else
        {
            var credentials = System.Text.ASCIIEncoding.ASCII
                        .GetString(Convert.FromBase64String(req.Headers["Authorization"].Substring(6)))
                        .Split(':');
            var user = new { Name = credentials[0], Password = credentials[1] };
            if(!(user.Name == "username" && user.Password == "passwords"))
            {
                filterContext.Result = new HttpNotFoundResult();
            }
        }
    }
}

1) Is an ActionFilterAttribute the best way to do this?

2) Is setting filterContext.Result the correct way to deny access to the controller method?

3) Is there anything I'm doing wrong?

Thanks.

-Nick


回答1:


1) Is an ActionFilterAttribute the best way to do this?
I think so. This approach mirrors the implementation of the built in Authorize attribute.

2) Is setting filterContext.Result the correct way to deny access to the controller method?
Yes. Thats whats it there for. (1)

3) Is there anything I'm doing wrong?

  • You assume that the content of the Authorization header is in the correct format and is correctly encoded.
  • You assume that the request is for basic authenication and not any other authentication scheme.
  • I would prefer to use HttpUnauthorizedResult() to send a http 401 error instead of a http 404 error via HttpNotFoundResult().

Below in my implementation of your code (which I'm sure has its issues too).

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        try
        {
            if (String.IsNullOrEmpty(filterContext.HttpContext.Request.Headers["Authorization"]))
            {
                filterContext.Result = new HttpUnauthorizedResult();
            }
            else
            {
                if (filterContext.HttpContext.Request.Headers["Authorization"].StartsWith("Basic ", StringComparison.InvariantCultureIgnoreCase))
                {
                    string[] credentials = ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(filterContext.HttpContext.Request.Headers["Authorization"].Substring(6))).Split(':');

                    if (credentials.Length == 2)
                    {
                        if (String.IsNullOrEmpty(credentials[0]))
                        {
                            filterContext.Result = new HttpUnauthorizedResult();
                        }
                        else if (!(credentials[0] == "username" && credentials[1] == "passwords"))
                        {
                            filterContext.Result = new HttpUnauthorizedResult();
                        }
                    }
                    else
                    {
                        filterContext.Result = new HttpUnauthorizedResult();
                    }
                }
                else
                {
                    filterContext.Result = new HttpUnauthorizedResult();
                }
            }

            base.OnActionExecuting(filterContext);
        }
        catch
        {
            filterContext.Result = new HttpUnauthorizedResult();
        }
    }

Notes

  • I haven't included illegal character checks for username and password.
  • I couldn't settle on how to implement exception handling so I have gone with simplicity.

References

(1) http://msdn.microsoft.com/en-us/magazine/gg232768.aspx




回答2:


Refactored version of Adrian's

public class BasicAuthenticationAttribute : ActionFilterAttribute
{
    private static readonly string AuthorizationHeader = "Authorization";
    private static readonly string BasicHeader = "Basic ";
    private static readonly string Username = "username";
    private static readonly string Password = "password";
    private static readonly char[] Separator = ":".ToCharArray();

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        try
        {
            if (!Authenticated(filterContext.HttpContext.Request))
                filterContext.Result = new HttpUnauthorizedResult();

            base.OnActionExecuting(filterContext);
        }
        catch
        {
            filterContext.Result = new HttpUnauthorizedResult();
        }
    }

    private bool Authenticated(HttpRequestBase httpRequestBase)
    {
        bool authenticated = false;

        if (String.IsNullOrEmpty(httpRequestBase.Headers[AuthorizationHeader]) == false &&
            httpRequestBase.Headers[AuthorizationHeader].StartsWith(BasicHeader, StringComparison.InvariantCultureIgnoreCase))
        {
            string[] credentials = Encoding.ASCII.GetString(Convert.FromBase64String(
                httpRequestBase.Headers[AuthorizationHeader].Substring(BasicHeader.Length))).Split(Separator);

            if (credentials.Length == 2 && credentials[0] == Username && credentials[1] == Password)
            {
                authenticated = true;
            }
        }

        return authenticated;
    }
}



回答3:


Here's a sort of official sample for basic authentication:

http://www.asp.net/web-api/overview/security/authentication-filters

Another article, now using OWIN:

https://lbadri.wordpress.com/2013/07/13/basic-authentication-with-asp-net-web-api-using-owin-middleware/




回答4:


1) No, ActionFilter attributes are not a good approach to authenticate a user. (As we need to authenticate once and set authenticate cookie, so HttpContext.User will remain authenticated till cookie expires)

2) Yes, setting filtercontext.Result is a ideal way to prevent access. ( But Instead of assigning HttpNotFoundResult, use RedirectResult to redirect to login page)

3) I really don't understand why to have such implementation for Authorization. The best approach would be to have an action that will receive form posted data (username and password). and use Authorize attribute to prevent unauthorize access.

following is the code from default MVC3 sample application in VS2010.

    [HttpPost]
    public ActionResult LogOn(LogOnModel model, string returnUrl)
    {
        if (ModelState.IsValid)
        {
            if (Membership.ValidateUser(model.UserName, model.Password))
            {
                FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                    && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                {
                    return Redirect(returnUrl);
                }
                else
                {
                    return RedirectToAction("Index", "Home");
                }
            }
            else
            {
                ModelState.AddModelError("", "The user name or password provided is incorrect.");
            }
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }


来源:https://stackoverflow.com/questions/9399568/asp-mvc-3-actionfilter-for-basic-authentication

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!