Using JWT with custom authentication filter in the Web API
See original GitHub issueHey there, and thanks for an amazing framework!
I’ve scoured the web for an issue about this, but couldn’t find one, so here goes.
I’m attempting to implement JWT, to authenticate mobile clients by a deviceToken (as the clients doesn’t use a login). I’ve followed the setup from: https://github.com/cuongle/WebApi.Jwt , using the same filters, and then inserting the following in the ProjectNameWebApiModule.cs:
//Outcommented "bearer" from original
Configuration.Modules.AbpWebApi().HttpConfiguration.Filters.Add(new JwtAuthenticationAttribute());
The authentication filter looks like this (same as the github link above):
public class JwtAuthenticationAttribute : Attribute, IAuthenticationFilter
{
public string Realm { get; set; }
public bool AllowMultiple => false;
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
var request = context.Request;
var authorization = request.Headers.Authorization;
if (authorization == null || authorization.Scheme != "Bearer")
{
context.ErrorResult = new AuthenticationFailureResult("Missing Jwt Token", request);
return;
}
if (string.IsNullOrEmpty(authorization.Parameter))
{
context.ErrorResult = new AuthenticationFailureResult("Missing Jwt Token", request);
return;
}
var token = authorization.Parameter;
var principal = await AuthenticateJwtToken(token);
if (principal == null)
context.ErrorResult = new AuthenticationFailureResult("Invalid token", request);
else
context.Principal = principal;
}
private static bool ValidateToken(string token, out string username)
{
username = null;
var simplePrinciple = JwtManager.GetPrincipal(token);
var identity = simplePrinciple.Identity as ClaimsIdentity;
if (identity == null)
return false;
if (!identity.IsAuthenticated)
return false;
var usernameClaim = identity.FindFirst(ClaimTypes.Name);
username = usernameClaim?.Value;
if (string.IsNullOrEmpty(username))
return false;
// More validate to check whether username exists in system
return true;
}
protected Task<IPrincipal> AuthenticateJwtToken(string token)
{
string username;
if (ValidateToken(token, out username))
{
// based on username to get more information from database in order to build local identity
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, username)
// Add more claims if needed: Roles, ...
};
var identity = new ClaimsIdentity(claims, "Jwt");
IPrincipal user = new ClaimsPrincipal(identity);
return Task.FromResult(user);
}
return Task.FromResult<IPrincipal>(null);
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
Challenge(context);
return Task.FromResult(0);
}
private void Challenge(HttpAuthenticationChallengeContext context)
{
string parameter = null;
if (!string.IsNullOrEmpty(Realm))
parameter = "realm=\"" + Realm + "\"";
context.ChallengeWith("Bearer", parameter);
}
}
The problem:
Above seems to work, however, when a token is not valid, I am not able to pass the error to the response. I get a standard 500-error response like this:
{
"result": null,
"targetUrl": null,
"success": false,
"error": {
"code": 0,
"message": "An internal error occurred during your request!",
"details": null,
"validationErrors": null
},
"unAuthorizedRequest": false,
"__abp": true
}
Questions:
- How does one go by extending this, so that the mobile client can react to the response?
- Are there any examples of a JWT integration like this, without a username/password?
Details:
.Net Framework, Abp version: 1.3.1 Username/password solution is not possible, as an anonymous approach must be taken.
Thank you.
Issue Analytics
- State:
- Created 6 years ago
- Comments:5 (2 by maintainers)
Top GitHub Comments
Does
line 47
refer tovar identity = simplePrinciple.Identity as ClaimsIdentity;
?Add a null-conditional operator:
Thanks for your assistance @acjh .
I ended up completely rewriting the authentication filter, from scratch, in order to understand it fully. After that, I’ve had no issues.
Thanks again 👍