问题描述:

I needed to support, in addition to standard out-of-the-box cookies/forms authentication, also Basic Authentication over HTTPS for SignalR. SignalR runs in the context of a mixed MVC/WebApi site.

After putting the pieces together how to implement this, I used ThinkTecture.IdentityModel.Owin.BasicAuthentication library for this on the server, like this:

app.Map("/basicauth", map =>

{

map.UseBasicAuthentication("realm", ValidateUser);

map.MapSignalR<AuthenticatedEchoConnection>("/echo");

map.MapSignalR();

});

But instead of returning a challenge, I always get a HTTP 302 response that redirects to the Login page of the MVC site. To better debug this, I quickly rolled my own simple OWIN middleware for basic authentication and got the same result. Further testing with a simple mapping like this:

app.Map("/test", map =>

{

map.Use((context, next) =>

{

// context.Response.StatusCode = 401;

context.Response.Write("Hello World!");

return Task.FromResult(0);

});

revealed that a simple "Hello World" response is returned normally. But when I comment out the the line that sets the response code to 401, I get the redirect to the Login page again. I do not understand this behavior ... why does my MVC site gets involved here and not the 401 response is returned? How can I prevent this?

For OWIN, besides the special /basicauth map above, I had only the top level SignalR mapping in the startup method defined that should continue to work for all cookie authenticated calls:

app.MapSignalR();

Nothing else had been configured by me for OWIN.

Can anybody help me with this?

网友答案:

Ok, I found a way to work around this issue. The first part is to throw out map.MapSignalR<AuthenticatedEchoConnection>("/echo"); from the first sample - it is not necessary and for some reason I not found out it prevented SignalR from working properly.

The second part, and the workaround for the actual problem, is that in the client I also send the credentials with the first request and do not wait for a challenge. Thus, a 401 never happens and so no redirect to login page. And that's good enough for me.

So the workaround is, in the client, do not use NetworkCredential like this:

connection.Credentials = new NetworkCredential(username, password);

Instead, add the Authorization header yourself so it is included already in the first request:

string creds = string.format("{0}:{1}", username, password);
string encodedCreds = Convert.ToBase64String(Encoding.Utf8.GetBytes(creds));
connection.Headers.Add("Authorization", "Basic " + encodedCreds);

In addition, what I found out is that with OWIN, this issue seems to be a more general one and not only related when used with SignalR or even Basic Auth:

http://brockallen.com/2013/10/27/using-cookie-authentication-middleware-with-web-api-and-401-response-codes/

Thus, with some modifications to the basic authentication module, it should also be possible to prevent this redirection. I might look into this and will update this post when done.

相关阅读:
Top