简体   繁体   中英

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.

Following Darin's code, I have created a WebApi project and added the following controllers and model:

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

I have created a Web Forms app with two buttons and a label for testing purposes.

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.

If I then click the ButtonTestAuthClick(), I get a 401 (Unauthorized) error.

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.

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. Turns out I had left the authentication mode in the web.config left at "None". Obviously, you have to turn on Forms Authentication here in order for the FormsAuthentication.SetAuthCookie() method to have any effect.

<authentication mode="Forms" />

Once I fixed this oversight, everything starting working fine. :-)

You are calling web api with authentication in the middle. Why not your don't authenticate the user on the client side by 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. All the cookie information won't be kept in the current request. In order to support this scenario, you need to handle the cookie by yourself.

For example: Set cookie ASPXAUTH to asp.net headers in ButtonAuthorizeClick method if the response has it. Set cookie ASPXAUTH to HttpRequestMessage and send it by 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. 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. The check-in seems not in the RTM release. You may try it's nightly build http://aspnetwebstack.codeplex.com/discussions/353867 .

Though it is late, The client in ButtonTestAuthClick is not the browser. It is the httpClient object here. Thus, you need to programmatically set the cookie generated from other button.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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