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

发布于 2025-01-07 17:34:46 字数 1072 浏览 1 评论 0原文

我有一个使用基本身份验证的 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)我做错了什么吗?

谢谢。

-缺口

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

痞味浪人 2025-01-14 17:34:46

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) 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

情归归情 2025-01-14 17:34:46

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

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;
    }
}
罗罗贝儿 2025-01-14 17:34:46

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

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);
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文