简体   繁体   中英

ASP.NET Core AWS Cognito JWT

In ASP.NET Core, how can I standardize the available user information AuthorizationHandlerContext.User when the JWT tokens pass different claims?

AWS Congito has two token types, access tokens, and id tokens. Id tokens contain claims for first name, last name, account Id, email, etc, while it's access token only contains the account Id claim.

How can I create a generic User object which get's populate depending on the token type?

Available ID Token claims AccountId, FirstName, LastName, Email, Phone

Available Access Token claims AccountId

Now somewhere else in my application I need to get the current user's first name. This isn't a problem with the ID token because it's already available, but I need to be able to go to my DB to fetch the user's first name, last name, email, and phone when an access token is sent.

I tried create my own user object which is registered with the DI Container, but IHttpContextAccessor passes an identity which isn't authenticated so there are zero claims available at that point.

//Startup.cs
public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(options => {
        options.DefaultAuthenticationScheme = JwtBearerDefault.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options => {
       //Omitted for brevity
    });

    services.AddAuthorization(options => {
        //Omitted for brevity
    });
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseAuthentication();
}

//MyUser.cs
//How can this class's properties be set depending on the access token type?
//IE set by the claims available in the ID token, but send by a DB query when the an access token is used.
class MyUser : IMyUser
{
     public int AccountId {get;set;}
     public string FirstName {get;set;}
     public string LastName {get;set;}
}

//MyService.cs
class MyService
{
    private IMyUser _user;

    public MyService(IMyUser user)
    {
        _user = user;
    }

    public MyMethod()
    {
       //Do something with _user.FirstName, _user.LastName
    }
}

//I tried passing IHttpContextAccessor as a constructor param in MyUser
//but context.User.Identity.Claims.Count = 0 and context.User.Identity.IsAuthenticated = false
//MyUser.cs
public MyUser(IHttpContextAccessor context){
    //context.User.Identity.IsAuthenticated == false
    //context.User.Identity.Claims.Count == 0
    //context.User.Identity.Name == null
}

如果您使用Amazon.Lambda.AspNetCoreServer,则只需在API网关中将cognito配置为身份验证,然后可以通过以下方式访问声明:

var claim = Request.HttpContext.User.Claims.First(x=>x.Type =="Foo").Value;

If you use the latest version of AspNetCoreServer, you can get all claims from the JWT token and have all of it attached with your Principal. However, you still need to configure your ASP.NET Core application to understand those claims and authenticate the user from the ASP.NET Core (application) perspective. I had the exact same issue and ended up creating a library for it .

With that, you can:

services.AddAuthentication(AwsJwtAuthorizerDefaults.AuthenticationScheme)
  .AddJwtAuthorizer(options =>
  {
      // In the case of local run, this option enables the extraction of claims from the token
      options.ExtractClaimsFromToken = true;
      
      // Validates the presence of the token
      options.RequireToken = true;
  });

If you still need more control about what to do with the token, you can create a custom AuthenticationHandler. Consider this example .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM