用于基本身份验证的asp mvc 3 ActionFilter

时间:2012-02-22 17:09:57

标签: asp.net-mvc-3 basic-authentication

我有一个使用基本身份验证的ASP MVC3 restful服务。搜索堆栈溢出后,我创建了以下代码。

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)ActionFilterAttribute是最好的方法吗?

2)设置filterContext.Result是否正确拒绝访问控制器方法?

3)我有什么问题吗?

感谢。

-Nick

4 个答案:

答案 0 :(得分:12)

1) ActionFilterAttribute这是最好的方法吗?
我认同。此方法反映了内置Authorize属性的实现。

2)是否设置filterContext.Result拒绝访问控制器方法的正确方法?
是。多数民众赞成在那里。 (1)

3)我有什么问题吗?

  • 您认为Authorization标头的内容位于 格式正确且编码正确。
  • 您认为该请求仅用于基本身份验证,而不是任何请求 其他认证方案。
  • 我更愿意使用HttpUnauthorizedResult()发送http 通过HttpNotFoundResult()发送401错误而不是http 404错误。

下面是我的代码实现(我肯定也有问题)。

    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();
        }
    }

备注

  • 我没有包含用户名和密码的非法字符检查。
  • 我无法解决如何实现异常处理的问题,所以我简单易行。

<强>参考

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

答案 1 :(得分:8)

Adrian的重构版本

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;
    }
}

答案 2 :(得分:-1)

答案 3 :(得分:-2)

1)不,ActionFilter属性不是验证用户身份的好方法。    (因为我们需要进行一次身份验证并设置身份验证cookie,因此HttpContext.User将保持身份验证,直到Cookie过期)

2)是的,设置filtercontext.Result是阻止访问的理想方法。 (但不是分配HttpNotFoundResult,而是使用RedirectResult重定向到登录页面)

3)我真的不明白为什么有这样的授权实现。 最好的方法是有一个接收表单发布数据(用户名和密码)的操作。并使用Authorize属性来防止取消授权访问。

以下是VS2010中默认MVC3示例应用程序的代码。

    [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);
    }