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

时间:2015-10-27 10:40:31

标签: c# asp.net asp.net-mvc basic-authentication antiforgerytoken

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

对于此测试阶段,我们决定从此link实施基本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及其验证。

3 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:1)

你在res.AppendHeader(..)之前试过这行吗?

Response.ClearHeaders();

答案 2 :(得分:1)

我认为您不想使用req.End()结束请求,而是设置filterContext.Result,如下所示。将Result设置为非null值将中断MVC管道的其余部分的处理并导致响应被发送到浏览器,但它不应该像End()那样密封响应,所以你不应该&# 39;获取有关已发送标头的例外情况。

试试这个:

filterContext.Result = new HttpUnauthorizedResult();