C# 身份验证筛选器:如何使用消息执行HTTP 401

C# 身份验证筛选器:如何使用消息执行HTTP 401,c#,asp.net,authentication,asp.net-web-api2,asp.net-web-api,C#,Asp.net,Authentication,Asp.net Web Api2,Asp.net Web Api,我随后做了一个自定义身份验证过滤器 一切正常,但我无法让服务器在401上说任何话。它正确地给出了www-authenicate标题和状态代码401,但没有内容/正文 我尝试使用来自的AuthenticationFailureResult。我将我的authenticatesync转换为async,并忽略了wait警告 这是我目前的工作,注释中的代码是我希望我能做的,就是让它使用任何格式化程序 //request.CreateResponse(HttpStatusCode.Unauthorized,

我随后做了一个自定义身份验证过滤器

一切正常,但我无法让服务器在401上说任何话。它正确地给出了
www-authenicate
标题和状态代码401,但没有内容/正文

我尝试使用来自的
AuthenticationFailureResult
。我将我的
authenticatesync
转换为
async
,并忽略了
wait
警告

这是我目前的工作,注释中的代码是我希望我能做的,就是让它使用任何格式化程序

//request.CreateResponse(HttpStatusCode.Unauthorized, new { Error = true, Message = "Token is invalid" });
HttpContext.Current.Response.ContentType = "application/json";
HttpContext.Current.Response.Write("{ \"Error\" = true, \"Message\" = \"Token is invalid\" }");
context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], request);

有两种选择可以做到这一点:快速但粗暴,更长但更优雅

A.直接修改HttpResponse:

HttpContext.Current.Response.StatusCode = 401;
HttpContext.Current.Response.Write("some content");
B.实现
ihttpackationresult
并在该类中设置
HttpResponseMessage
Content
属性:

public class AuthenticationFailureResult : IHttpActionResult
{
    public AuthenticationFailureResult(object jsonContent, HttpRequestMessage request)
    {
        JsonContent = jsonContent;
        Request = request;
    }

    public HttpRequestMessage Request { get; private set; }

    public Object JsonContent { get; private set; }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult(Execute());
    }

    private HttpResponseMessage Execute()
    {
        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
        response.RequestMessage = Request;
        response.Content = new ObjectContent(JsonContent.GetType(), JsonContent, new JsonMediaTypeFormatter());
        return response;
    }
}

注意:如果要对
JsonContent
使用匿名类型,请确保
AuthenticationFailureResult
在同一个库中实现。

如果要随401响应附加消息,我认为应该这样做。这就是我在项目中所做的:

public class TokenAuthenticationAttribute : AuthorizeAttribute
{
    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        // Do your authentication here
    }

    protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
    {
        if (actionContext == null)
        {
            throw new ArgumentNullException("actionContext", "Null actionContext");
        }

        actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
        actionContext.Response.Headers.Add("AuthenticationStatus", "NotAuthorized");
        actionContext.Response.ReasonPhrase = "Authentication failed";

        // Create your content here (I use Student class as an example)
        actionContext.Response.Content = new ObjectContent(
            typeof (Student),
            new Student("Forte", 23),
            new JsonMediaTypeFormatter());
    }
}
学生班级:

public class Student
{
    public string Name { get; set; }
    public int Age { get; set; }

    public Student(string name, int age)
    {
        Name = name;
        Age = age;
    }
}
然后,我这样使用它:

context.ErrorResult = new AuthenticationFailureResult(new { Error = true, Message = "Token is invalid" }, request);
[TokenAuthentication]
public class DocumentController : ApiController
{
    // Your code here
}
编辑

感谢评论中的
wal
建议,以下是一种将消息附加到响应的较短方式:

actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized,
                new {Error = true, Message = "Token is invalid"});
然后,您的回复信息将是:

{"$id":"1","error":true,"message":"Token is invalid"}

通过这种方式,您不必再设置
actionContext.Response.Content

这看起来像是一种黑客方式,因为它不使用我的JSON解析器。我的尝试是
request.CreateResponse(HttpStatusCode.Unauthorized,new{Error=true,Message=“Token is invalid”,})但我无法让它工作。在第二个链接的示例中有一个
AuthenticationFailureResult
类。如果您实现了该示例中的IActionResult,您可以在
Execute()
方法中设置
HttpResponseMessage
类的
Content
属性。当我设置Content属性时,这不会给我任何输出设置Content属性时,这不会给我JSON输出。我必须使用Content=newstringcontent,它绕过了JSON格式化程序,所以直接设置内容不是我想要的。是的,这真是令人费解。不过我找到了这个话题。它说应该用
MediaTypeFormatter
设置内容,如下所示:
response.content=newObjectContent(typeof(T)、objectInstance、MediaTypeFormatter)
请注意返回JSON而不是
StringContent
您可以使用
actionContext.Response=actionContext.Request.CreateResponse(new{Error=true,Message=“Token is invalid”})那个编辑实际上并没有好多少。将对象传递到
Request.CreateResponse
调用中(或使用anon类)。您不需要
JsonMediaTypeFormatter
-如果您按照我的方式执行,那么它将满足被调用方在
接受
标题中的请求,但我不明白。你能建议一个更好的方法吗?:)你能看到你写的这句话吗
actionContext.Response=actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized)将其替换为我在第一条评论中写的内容,然后删除此行
actionContext.Response.Content…
try
actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized,new{Error=true,Message=“Token is invalid”})