How to have custom validation of a JWT bearer toke

2019-08-30 06:52发布

问题:

I have in incoming bearer token that has an incorrect audience. There is enough information in the token via other claims that prove what the audience should be. I was hoping to fix it up early so that I could still take advantage of the JwtBearerOptions.TokenValidationParameters.ValidateAudience = true; JwtBearerOptions.TokenValidationParameters.ValidAudiences ={"the right one"};

I can hook the OnTokenValidated event, and rewrite the principal, but that is too late. Earlier in the pipeline the token has been validated and since the audience is wrong, it has already been rejected.

I am able to get around this by using authorization policies, by setting ValidateAudience=false and taking care of this at the controller level. I don't like having to add that [Authorize("the-correct-audience")] attribute to every controller, because someone will miss one.

Another alternative is to introduce a new middleware that works on the identitiy.claims and reject there.

In the end I want to be able to globally reject these tokens the way a validateAudience = true accomplishes, when validateAudience has been taken away from me as a filtering option.

Has anyone done something like this and what other alternatives have you used?

回答1:

Solution 1: Solve it by introducing a middleware. NOTE: Don't validate the audience

  1. First hook the following;

```

 JwtBearerOptions = options =>{
 options.Events = new JwtBearerEvents
{
 OnTokenValidated = context =>
 {
    ...
    // this will put in the right aud
    // replace the entire principal
    var appIdentity = new ClaimsIdentity(newClaims);
    var claimsPrincipal = new ClaimsPrincipal(appIdentity);
    context.Principal = claimsPrincipal;
    }
  }
}
  1. Introduce this middleware;
    I am looking for aud here, but you everything is fair game in the identity.

```

app.UseAuthentication();
app.Use(async (HttpContext context, Func<Task> next) =>
{
            //do work before the invoking the rest of the pipeline       
            if (context.Request.Headers.ContainsKey("x-authScheme") &&
                context.Request.Headers.ContainsKey("Authorization") &&
                context.User != null)
            {
                // looking for bearer token stuff.
                var claims = context.User.Claims;
                var q = from claim in claims
                    where claim.Type == "aud" && claim.Value == "aggregator_service"
                    select claim;
                if (!q.Any())
                {
                    context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                    return;
                }
            }

            await next.Invoke(); //let the rest of the pipeline run

            //do work after the rest of the pipeline has run     
});

```