Reputation: 148524
I wanted to add a principle onto the thread by myself , without using the Identity mechanism which really reminds me the old membership/forms authentication mechanics.
So I've managed (successfully) to create a request with principle :
MyAuthMiddleware.cs
public class MyAuthMiddleware
{
private readonly RequestDelegate _next;
public MyAuthMiddleware(RequestDelegate next )
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
var claims = new List<Claim>
{
new Claim("userId", "22222222")
};
ClaimsIdentity userIdentity = new ClaimsIdentity(claims ,"MyAuthenticationType");
ClaimsPrincipal principal = new ClaimsPrincipal(userIdentity);
httpContext.User = principal;
await _next(httpContext);
}
}
The Configure method:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//app.UseAuthentication(); //removed it. I will set the thread manually
if (env.IsDevelopment()) app.UseDeveloperExceptionPage();
app.UseMyAuthMiddleware(); // <---------- Myne
app.UseMvc();
app.Run(async context => { await context.Response.WriteAsync("Hello World!"); });
}
And here is the Action in the Controller: (Notice Authorize attribute)
[HttpGet]
[Route("data")]
[Authorize]
public IActionResult GetData()
{
var a=User.Claims.First(f => f.Type == "userId");
return new JsonResult(new List<string> {"a", "b",a.ToString() , User.Identity.AuthenticationType});
}
Ok Let's try calling this method, Please notice that this does work :
So where is the problem 😊?
Please notice that there is an [Authorize]
attribute. Now let's remove
setting principle on the thread ( by removing this line ) :
//httpContext.User = principal; // line is remarked
But now when I navigate to :
http://localhost:5330/api/cities/data
I'm being redirected to :
http://localhost:5330/Account/Login?ReturnUrl=%2Fapi%2Fcities%2Fdata
But I'm expecting to see Unauthorized error.
I'm after WebApi alike responses. This is not a website but an API.
Question:
Why don't I see the Unauthorized error ? And how can I make it appear?
Nb here is my ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication( CookieAuthenticationDefaults.AuthenticationScheme )
.AddCookie( CookieAuthenticationDefaults.AuthenticationScheme, a =>
{
a.LoginPath = "";
a.Cookie.Name = "myCookie";
});
services.AddMvc();
}
EDIT
Currently What I've managed to do is to use OnRedirectionToLogin :
But it will be really disappointing if that's the way to go. I'm expecting it to be like webapi.
Upvotes: 7
Views: 2524
Reputation: 93043
The default implementation of the OnRedirectToLogin
delegate looks like this:
public Func<RedirectContext<CookieAuthenticationOptions>, Task> OnRedirectToLogin { get; set; } = context =>
{
if (IsAjaxRequest(context.Request))
{
context.Response.Headers["Location"] = context.RedirectUri;
context.Response.StatusCode = 401;
}
else
{
context.Response.Redirect(context.RedirectUri);
}
return Task.CompletedTask;
};
As is clear from the code above, the response that gets sent to the client is dependent upon the result of IsAjaxRequest(...)
, which itself looks like this:
private static bool IsAjaxRequest(HttpRequest request)
{
return string.Equals(request.Query["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal) ||
string.Equals(request.Headers["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal);
}
This means that the response will be a 401
redirect if either a X-Requested-With
request header or query-string value is set to XMLHttpRequest
. When you hit your endpoint directly from the browser or from within e.g. Fiddler, this value is not set and so the response is a 302
, as observed. Otherwise, when using XHR or Fetch in the browser, this value gets set for you as a header and so a 401
is returned.
Upvotes: 4