简体   繁体   English

ASP.NET WebApi FormsAuthentication 401(未经授权)问题

[英]ASP.NET WebApi FormsAuthentication 401 (Unauthorized) issue

I have been learning how authorization works in ASP.Net WebApi and I came across an answer by Darin Dimitrov in another posting ( ASP.NET Web API Authentication ) and I need some help understanding why I'm getting a 401. 我一直在学习授权在ASP.Net WebApi中的工作方式,并且在另一篇文章( ASP.NET Web API身份验证 )中遇到了达林·迪米特洛夫(Darin Dimitrov)的回答,我需要一些帮助来理解为什么我会收到401。

Following Darin's code, I have created a WebApi project and added the following controllers and model: 按照Darin的代码,我创建了一个WebApi项目并添加了以下控制器和模型:

AccountController.cs AccountController.cs

using System.Web.Http;
using System.Web.Security;
using AuthTest.Models;

namespace AuthTest.Controllers
{
    public class AccountController : ApiController
    {
        public bool Post(LogOnModel model)
        {
            if (model.Username == "john" && model.Password == "secret")
            {
                FormsAuthentication.SetAuthCookie(model.Username, false);
                return true;
            }

            return false;
        }
    }
}

UsersController.cs UsersController.cs

using System.Web.Http;

namespace AuthTest.Controllers
{
    [Authorize]
    public class UsersController : ApiController
    {
        public string Get()
        {
            return "This is top secret material that only authorized users can see";
        }
    }
}

LogOnModel.cs LogOnModel.cs

namespace AuthTest.Models
{
    public class LogOnModel
    {
        public string Username { get; set; }
        public string Password { get; set; }
    }
}

I have created a Web Forms app with two buttons and a label for testing purposes. 我创建了一个带有两个按钮和一个标签的Web窗体应用程序,用于测试。

Default.aspx.cs Default.aspx.cs

using System;
using System.Net.Http;
using System.Threading;

namespace AuthTestWebForms
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }

        protected void ButtonAuthorizeClick(object sender, EventArgs e)
        {
            using (var httpClient = new HttpClient())
            {
                var response = httpClient.PostAsJsonAsync(
                    "http://localhost/authtest/api/account",
                    new { username = "john", password = "secret" },
                    CancellationToken.None
                ).Result;
                response.EnsureSuccessStatusCode();

                bool success = response.Content.ReadAsAsync<bool>().Result;
                if (success)
                {
                    //LabelResponse.Text = @"Credentials provided";
                    var secret = httpClient.GetStringAsync("http://localhost/authtest/api/users");
                    LabelResponse.Text = secret.Result;
                }
                else
                {
                    LabelResponse.Text = @"Sorry, you provided the wrong credentials";
                }
            }
        }

        protected void ButtonTestAuthClick(object sender, EventArgs e)
        {
            using (var httpClient = new HttpClient())
            {
                var secret = httpClient.GetStringAsync("http://localhost/authtest/api/users");
                LabelResponse.Text = secret.Result;
            }
        }
    }
}

When I click the button and run ButtonAuthorizeClick() it fires the controller for Account and then fires the controller for Users and everything is fine. 当我单击按钮并运行ButtonAuthorizeClick()时,它为Account触发控制器,然后为Users触发控制器,一切正常。

If I then click the ButtonTestAuthClick(), I get a 401 (Unauthorized) error. 如果再单击ButtonTestAuthClick(),则会收到401(未经授权)错误。

When I look for the ASPXAUTH cookie in Chrome or FireFox, I don't see one, so I'm not 100% sure why ButtonAuthorizeClick() works and what I need to do to make ButtonTestAuthClick() work. 当我在Chrome或FireFox中寻找ASPXAUTH cookie时,没有看到它,因此我不确定100%为什么ButtonAuthorizeClick()可以工作,以及我需要做什么来使ButtonTestAuthClick()起作用。

Thanks for any help anybody can throw my way. 感谢您的帮助,任何人都可以抛弃我。

I was having a similar problem, though not via a Web Forms client page but rather with JavaScript and AJAX calls. 我遇到了类似的问题,虽然不是通过Web窗体客户端页面,而是通过JavaScript和AJAX调用。 Turns out I had left the authentication mode in the web.config left at "None". 原来我已将身份验证模式留在web.config中的“无”位置。 Obviously, you have to turn on Forms Authentication here in order for the FormsAuthentication.SetAuthCookie() method to have any effect. 显然,为了使FormsAuthentication.SetAuthCookie()方法生效,您必须在此处打开Forms Authentication。

<authentication mode="Forms" />

Once I fixed this oversight, everything starting working fine. 一旦我纠正了这一疏忽,一切都会开始正常。 :-) :-)

You are calling web api with authentication in the middle. 您正在调用带有身份验证的Web API。 Why not your don't authenticate the user on the client side by ajax? 为什么不通过ajax不对客户端的用户进行身份验证?

The problem here is everytime your send a request to web api by HttpClient, it actually is a new web request handled by server. 这里的问题是每次您通过HttpClient向Web api发送请求时,它实际上是服务器处理的新Web请求。 All the cookie information won't be kept in the current request. 所有cookie信息都不会保留在当前请求中。 In order to support this scenario, you need to handle the cookie by yourself. 为了支持这种情况,您需要自己处理cookie。

For example: Set cookie ASPXAUTH to asp.net headers in ButtonAuthorizeClick method if the response has it. 例如:如果响应中包含Cookie ASPXAUTH,则将其设置为ButtonAuthorizeClick方法中的asp.net标头。 Set cookie ASPXAUTH to HttpRequestMessage and send it by HttpClient. 将cookie ASPXAUTH设置为HttpRequestMessage并由HttpClient发送。

Web api recently added a support to use HttpServer to create in-proc server and can directly send request to the current message handler in current process. Web API最近添加了对使用HttpServer来创建进程内服务器的支持,并且可以将请求直接发送到当前进程中的当前消息处理程序。 So you can write code like: 因此,您可以编写如下代码:

HttpClient c = new HttpClient(new HttpServer(GlobalConfiguration.DefaultHandler));
c.GetStringAsync("http://localhost/api/Values").Wait();

To send your request in-proc, so that the cookie header set in the web api action will still in the pipeline of the current request. 要将请求发送到进程内,以便在Web api操作中设置的cookie标头仍将在当前请求的管道中。 The check-in seems not in the RTM release. 签入似乎不在RTM版本中。 You may try it's nightly build http://aspnetwebstack.codeplex.com/discussions/353867 . 您可以尝试每晚进行构建http://aspnetwebstack.codeplex.com/discussions/353867

Though it is late, The client in ButtonTestAuthClick is not the browser. 尽管已经晚了,但ButtonTestAuthClick中的客户端不是浏览器。 It is the httpClient object here. 这是httpClient对象。 Thus, you need to programmatically set the cookie generated from other button. 因此,您需要以编程方式设置从其他按钮生成的cookie。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM