【问题标题】:authentication filter: How to do a HTTP 401 with message身份验证过滤器:如何使用消息执行 HTTP 401
【发布时间】:2015-12-22 12:35:15
【问题描述】:

我跟着http://bitoftech.net/2014/12/15/secure-asp-net-web-api-using-api-key-authentication-hmac-authentication/做了一个自定义认证过滤器。

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

我尝试使用来自http://www.asp.net/web-api/overview/security/authentication-filtersAuthenticationFailureResult,但没有帮助。我将AuthenticateAsync 转换为async 并忽略了await 警告。

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

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

【问题讨论】:

    标签: c# asp.net authentication asp.net-web-api2 asp.net-web-api


    【解决方案1】:

    有两种选择:快速但粗暴,更长但更优雅

    A.直接修改HttpResponse:

    HttpContext.Current.Response.StatusCode = 401;
    HttpContext.Current.Response.Write("some content");
    

    B.实现IHttpActionResult 并在该类中设置HttpResponseMessageContent 属性:

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

    那么你就可以这样使用它了:

    context.ErrorResult = new AuthenticationFailureResult(new { Error = true, Message = "Token is invalid" }, request);
    

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

    【讨论】:

    • 这看起来很老套,因为它不使用我的 JSON 解析器。我的尝试是request.CreateResponse(HttpStatusCode.Unauthorized, new { Error = true, Message = "Token is invalid", });,但我无法让它工作。
    • 第二个链接的示例中有一个 AuthenticationFailureResult 类。如果您已经像该示例中那样实现了 IActionResult,您可以在 Execute() 方法中设置 HttpResponseMessage 类的 Content 属性。
    • 设置 Content 属性时没有给我任何输出
    • 当我设置 Content 属性时,这并没有给我 JSON 输出。我必须使用 Content = new StringContent 绕过 JSON 格式化程序,所以直接设置内容不是我想要的。
    • 是的,这真的很令人费解。我通过stackoverflow.com/questions/12563576/… 找到了这个话题。它说内容应该像这样设置MediaTypeFormatterresponse.Content = new ObjectContent(typeof(T), objectInstance, mediaTypeFormatter);
    【解决方案2】:

    如果您想在 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;
        }
    }
    

    然后,我这样使用它:

    [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 而不是 StringContent 你可以使用 actionContext.Response = actionContext.Request.CreateResponse(new {Error = true, Message = "Token is invalid"});
    • 那个编辑真的好不了多少。将您的对象传递给Request.CreateResponse 调用(或使用匿名类)。你不需要JsonMediaTypeFormatter - 如果你按照我的方式做,那么它将尊重被调用者在Accept 标头中请求的内容
    • 对不起,我不明白。你能推荐一个更好的方法吗? :)
    • 你能看到你写的这行吗? actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized); 将其替换为我在第一条评论中写的内容,然后删除此行 actionContext.Response.Content...
    • tryactionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, new { Error = true, Message = "Token is invalid" })
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 2015-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-14
    相关资源
    最近更新 更多