【问题标题】:ASP.NET WebApi FormsAuthentication 401 (Unauthorized) issueASP.NET WebApi FormsAuthentication 401(未经授权)问题
【发布时间】:2012-10-02 18:45:49
【问题描述】:

我一直在学习授权在 ASP.Net WebApi 中的工作原理,我在另一篇帖子 (ASP.NET Web API Authentication) 中遇到了 Darin Dimitrov 的回答,我需要一些帮助来理解为什么我会得到 401。

按照 Darin 的代码,我创建了一个 WebApi 项目并添加了以下控制器和模型:

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

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

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

我创建了一个带有两个按钮和一个标签的 Web 表单应用程序,用于测试目的。

默认.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;
            }
        }
    }
}

当我单击按钮并运行 ButtonAuthorizeClick() 时,它会触发 Account 的控制器,然后触发 Users 的控制器,一切都很好。

如果我随后单击 ButtonTestAuthClick(),则会收到 401(未经授权)错误。

当我在 Chrome 或 FireFox 中查找 ASPXAUTH cookie 时,我没有看到,因此我不能 100% 确定 ButtonAuthorizeClick() 为何有效以及我需要做什么才能使 ButtonTestAuthClick() 有效。

感谢任何人都可以帮助我。

【问题讨论】:

    标签: c# authorization asp.net-web-api asp.net-authorization


    【解决方案1】:

    虽然晚了,但ButtonTestAuthClick中的客户端不是浏览器。它是这里的 httpClient 对象。因此,您需要以编程方式设置从其他按钮生成的 cookie。

    【讨论】:

      【解决方案2】:

      我遇到了类似的问题,虽然不是通过 Web 窗体客户端页面,而是通过 JavaScript 和 AJAX 调用。原来我已将 web.config 中的身份验证模式保留为“无”。显然,您必须在此处打开 Forms Authentication 才能使 FormsAuthentication.SetAuthCookie() 方法生效。

      <authentication mode="Forms" />
      

      一旦我解决了这个疏忽,一切都开始正常了。 :-)

      【讨论】:

      • 当...我的测试应用程序和 api 都设置了“表单”,但我仍然得到相同的响应。不过,谢谢您的回答。
      【解决方案3】:

      您正在调用 web api,中间有身份验证。为什么不通过 ajax 在客户端对用户进行身份验证?

      这里的问题是每次你通过 HttpClient 向 web api 发送请求时,它实际上是由服务器处理的一个新的 web 请求。所有 cookie 信息都不会保留在当前请求中。为了支持这种场景,你需要自己处理cookie。

      例如:如果响应中有,则在 ButtonAuthorizeClick 方法中将 cookie ASPXAUTH 设置为 asp.net 标头。 设置cookie ASPXAUTH 为HttpRequestMessage 并通过HttpClient 发送。

      Web api 最近增加了使用HttpServer 创建进程内服务器的支持,可以在当前进程中直接向当前消息处理程序发送请求。所以你可以编写如下代码:

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

      在进程中发送您的请求,以便在 web api 操作中设置的 cookie 标头仍将在当前请求的管道中。签入似乎不在 RTM 版本中。你可以试试它的夜间构建http://aspnetwebstack.codeplex.com/discussions/353867。

      【讨论】:

        猜你喜欢
        • 2016-12-14
        • 2017-03-20
        • 1970-01-01
        • 2021-09-28
        • 2017-10-26
        • 1970-01-01
        • 2014-09-12
        • 1970-01-01
        • 2011-08-02
        相关资源
        最近更新 更多