ASP.NET MVC5基本HTTP身份验证和AntiForgeryToken异常

11

我正在处理一个启用表单身份验证的ASP.NET MVC5项目。该项目目前处于测试阶段,在Azure上托管在线,但是项目所有者希望禁用对站点的所有公共访问(因为站点的某些部分根本不需要用户进行身份验证)。

在这个测试阶段,我们决定实现基本的HTTP身份验证,参考了这个链接。我修改了代码,以更好地满足我的需求:

public class BasicAuthenticationAttribute : FilterAttribute, IAuthorizationFilter
{
    public string BasicRealm { get; set; }

    protected string Username { get; set; }
    protected string Password { get; set; }

    public BasicAuthenticationAttribute(string username, string password)
    {
        this.Username = username;
        this.Password = password;
    }

    public void OnAuthorization (AuthorizationContext filterContext)
    {
        var req = filterContext.HttpContext.Request;
        var auth = req.Headers["Authorization"];
        if (!String.IsNullOrEmpty(auth))
        {
            var cred = System.Text.ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
            var user = new { Name = cred[0], Pass = cred[1] };

            if (user.Name == Username && user.Pass == Password) 
                return;
        }

        var res = filterContext.HttpContext.Response;
        var alreadySent = HttpContext.Current.Items.Contains("headers-sent");

        if (!alreadySent)
        {
            res = filterContext.HttpContext.Response;
            res.StatusCode = 401;
            res.AppendHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Test"));

        }
    }
}

我也将其注册为全局过滤器:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorExtendedAttribute());
        filters.Add(new BasicAuthenticationAttribute(AppConfig.BasicUsername, AppConfig.BasicPassword));
    }
}

然而,当我运行项目时,出现了一些问题。如果我使用这个版本的代码:

        if (!alreadySent)
        {
            res = filterContext.HttpContext.Response;
            res.StatusCode = 401;
            res.AppendHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Test"));
        }
在成功登录后,它会不断地重定向到表单登录页面。
然而,如果我附加:
res.End();

之后

res.AppendHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Test"));

cshtml文件中的Antiforgerytoken引发System.Web.HttpException异常

HTTP标头已发送后,服务器无法附加标头。

但在这种情况下,它最终成功验证。

我目前被困在这个问题上,不知道如何解决,因为关闭表单身份验证不是一个选项,而且我不能删除所有AntiForgeryTokens及其验证。


2
你为什么选择这种方法?如果你想要构建一个自定义的“身份验证过滤器”,你应该继承AuthorizeAttribute,重写IsAuthorized函数,在未经授权的请求中返回false并在HandleUnauthorizedRequest函数中处理它们。 - Triet Doan
如果您将res.StatusCode行与res.AppendHeader行交换,会发生什么? StatusCode值是否计入“Body”的一部分,从而关闭了对任何其他Headers的编写?还请考虑以下Andrew的回复。 - Sql Surfer
请不要使用基本身份验证。请注意,您参考的其他问题已经有6年历史了,即使在那时也有更好的替代方案。请参阅:http://adrianotto.com/2013/02/why-http-basic-auth-is-bad/ - nothingisnecessary
3个回答

3

我建议您使用ASP.NET Identity成员身份提供程序,因为它已包含在MVC 5中。使用此方法,您可以简单地验证用户身份,而不需要像以前的Membership一样编写大量代码。它还可以使用内部cookie进行外部登录,就像使用FormsAuthentication方法一样。您所需做的就是在代码中进行简单配置,而无需编写自定义过滤器。


1
你以前尝试过在 res.AppendHeader(..) 之前使用这行代码吗?
Response.ClearHeaders();

1

不要使用req.End()来结束请求,你需要像下面所示设置filterContext.Result。将结果设置为非空值将中断其余MVC管道的处理并导致响应发送到浏览器,但它不应该像End()一样封闭响应,因此你不应该收到关于头已经被发送的异常。

请尝试以下操作:

filterContext.Result = new HttpUnauthorizedResult();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接