Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access JWT User.Claims in class library

I've structured my project using DDD, it looks like this:

| CompanyName.API
  | MyControllerThatRequiresJwtToken << Entry point
| CompanyName.Application
| CompanyName.Data
  | EfCoreContext << I would like to get the claims here
| CompanyName.Domain
| CompanyName.IoC
| CompanyName.Test
| CompanyName.UI

I am using Z.EntityFramework.Plus.Audit.EFCore to audit all data changes. I added it to the CompanyName.Data project as this is where my EF Context lives.

Problem is: all requests in the API require a JWT token. I'd like to set the username of the person sending the request in the Audit object that will be saved into the database, however I don't have access to the HttpContext in my data layer.

What would be the best approach to get this information? Injecting IHttpContextAccessor into the data layer perhaps? It doesn't sound like a good plan to make the data layer "Http dependent".

UPDATE

I am not sure how I'd pass it from the Controller to the context. I believe it would need to be injected somehow.

Snippet of EfCoreContext.cs

public override int SaveChanges()
{
   var audit = new Audit();
   audit.CreatedBy = "JWT Username"; // << I'd need it here

   audit.PreSaveChanges(this);
   var rowAffecteds = base.SaveChanges();
   audit.PostSaveChanges();

   if (audit.Configuration.AutoSavePreAction != null)
   {
      audit.Configuration.AutoSavePreAction(this, audit);
      base.SaveChanges();
   }

   return rowAffecteds;
}
like image 360
AndreFeijo Avatar asked Oct 26 '25 17:10

AndreFeijo


1 Answers

Create an interface called IApplicationUser for instance. Give it readonly properties you need like id, name and what not.

Create an implementation of it

public class ApplicationUser : IApplicationUser
{
   private readonly IHttpContextAccessor httpContextAccessor;

   public ApplicationUser(IHttpContextAccessor httpContextAccessor)
   {
      this.httpConntextAccessor = httpContextAccessor;
   }

   public Guid Id => this.GetUserId();

   public string Name => this.GetUserName();

   private Guid GetUserId()
   {
       var subject = this.httpContextAccessor.HttpContext
                         .User.Identity.Claims
                         .FirstOrDefault(claim => claim.Type == JwtClaimTypes.Subject);

       return Guid.TryParse(subject, out var id) ? id : Guid.Empty;
   }

   private Guid GetUserId()
   {
       return this.httpContextAccessor.HttpContext
                         .User.Identity.Claims
                         .FirstOrDefault(claim => claim.Type == JwtClaimTypes.PreferredUserName);
   }
}

Now register that with your DI-Container. For default MS IOC:

services.AddScoped<IApplicationUser, ApplicationUser>();

Inject IApplicationUser where ever you need and use it to get user-information.

Edit: IHttpContextAccessor must be registered. If it isn't the case, do it like that as well

services.AddScoped<IHttpContextAccessor, HttpContextAccessor>();

Edit 2: Just to clarify. This is not meant to be used in a repository or however you would like to call it. Rethink your logic so you can pass that information to your entity before saving data.

like image 127
alsami Avatar answered Oct 29 '25 07:10

alsami



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!