Reputation: 5946
This is the page where I "learned" how to do it: https://stormpath.com/blog/token-authentication-asp-net-core
But for me this is not working (doesn't work with Fiddler, too) There is this controller for my ApplicationUser-model:
[Authorize] //works when it's not set, doesn't work when it's set
[Route("api/[controller]")]
public class ApplicationUserController : Controller
{
private IRepository<ApplicationUser> _applicationUserRepository;
public ApplicationUserController(IRepository<ApplicationUser> applicationUserRepository)
{
_applicationUserRepository = applicationUserRepository;
}
[HttpGet("{id}")]
public ApplicationUser Get(int id)
{
return _applicationUserRepository.Get(id);
}
}
and there's my wrapper for RestSharp to get all applicationusers:
public Task<T> GetResponseContentAsync<T>(string resource, int id) where T : new()
{
RestRequest request = new RestRequest($"{resource}/{{id}}", Method.GET);
request.AddUrlSegment("id", id);
if (!AuthenticationToken.IsNullOrEmpty(true))
{
request.AddHeader("Authorization", string.Format("Bearer {0}", AuthenticationToken));
_client.Authenticator = new JwtAuthenticator(AuthenticationToken);
_client.Authenticator.Authenticate(_client, request);
}
TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
_client.ExecuteAsync<T>(request, response =>
{
tcs.SetResult(response.Data);
});
return tcs.Task;
}
From my web-client application I want to login with JWT (Token-Authentication) what works. After login I get e.g. this access_token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJURVNUIiwianRpIjoiZTBjYjE0NjgtYzBmOS00ZTM4LTg4ZjgtMGM4ZjNmYjMyNjZmIiwiaWF0IjoxNDcwOTUwMTA0LCJuYmYiOjE0NzA5NTAxMDQsImV4cCI6MTQ3MDk1MDQwNCwiaXNzIjoiRXhhbXBsZUlzc3VlciIsImF1ZCI6IkV4YW1wbGVBdWRpZW5jZSJ9.a9_JK2SG3vzc6NSOB0mZXqHlM9UAEXUHHrrijAQUsX0
without the Authorize
-attribute I get the ApplicationUser, but when setting the Attribute, the result is null (since the web-api is not getting called)
the wrapper-call looks like this:
//this works, token-value is set
string token = new RepositoryCall("http://localhost:54008/").Login("token", "TEST", "TEST123");
string accessToken = JsonConvert.DeserializeObject<Dictionary<string, string>>(token)["access_token"];
ViewData["Result"] = accessToken;
ApplicationUser userAfterLogin = await new RepositoryCall("http://localhost:54008/api")
{ AuthenticationToken = accessToken }
.GetResponseContentAsync<ApplicationUser>("ApplicationUser", 2);
and here userAfterLogin
is null.
I'm trying to get the login since two weeks but I still don't get it right..
Any idea what I'm doing wrong? Maybe a wrong request-header-value for authorization?
Update
this is my Startup.Configure where I configured to use the Bearer / JWT:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseIdentity();
var secretKey = "mysupersecret_secretkey!123";
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
// Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715
var options = new TokenProviderOptions
{
Audience = "ExampleAudience",
Issuer = "ExampleIssuer",
SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256),
};
var tokenValidationParameters = new TokenValidationParameters
{
// The signing key must match!
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
// Validate the JWT Issuer (iss) claim
ValidateIssuer = true,
ValidIssuer = "ExampleIssuer",
// Validate the JWT Audience (aud) claim
ValidateAudience = true,
ValidAudience = "ExampleAudience",
// Validate the token expiry
ValidateLifetime = true,
// If you want to allow a certain amount of clock drift, set that here:
ClockSkew = TimeSpan.Zero
};
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = tokenValidationParameters
});
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
AuthenticationScheme = "Cookie",
CookieName = "access_token",
TicketDataFormat = new CustomJwtDataFormat(
SecurityAlgorithms.HmacSha256,
tokenValidationParameters)
});
app.UseMiddleware<TokenProviderMiddleware>(Options.Create(options));
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
Upvotes: 16
Views: 11651
Reputation: 51
If you recive authorizacion error or using postman you realize that you are being asked to redirect to login just decorate your class with:
[Authorize(AuthenticationSchemes = "Bearer")]
By default .Net uses cookie based auth, with that annotation you swicht to token based one
Upvotes: 1
Reputation: 500
In Fiddler you would see, if you are redirected to login page (it would report 2 Results, one with 302 (redirect) and then the 404 - is that the case?
You have DebugLogger activated, so try AddDebug(LogLevel.Trace) and view the Debug output window, it is very helpful in analysing which of authentication steps fail. It also shows if authentication fails or authorization, and if has a valid token etc. So it points to the direction to look for problems.
Upvotes: 0
Reputation: 531
So you are using 2 middlewares for identity. One provided by asp.net identity (cookie based) and another token based. Now both of the middleware use the same attribute for handling the request [Authorize]. More precisely look at the code here
for JWTBearer
and
for Cookie
Because both are activated in middleware pipeline the principal will have the data when you send auth token or cookie.
But because both of them are active either of them will return Unauthorized for the request that doesnt have cookie or JwtBearer.
For the solution you are looking for you need to create a middleware on top of existing cookie and token based to route the request to either based on if authorization header is present.
Upvotes: -1