Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF Core: Get Authenticated username in Shadow Properties

As a part of logging who entered/updated the data I am adding 4 common fields (Created By, Created Date, Modified By, Modified Date) in all entities. For this, I am using shadow properties feature suggested in multiple forums including https://dotnetcore.gaprogman.com/2017/01/26/entity-framework-core-shadow-properties/

My question is how do I get information about authenticated user ?. If it was a controller I could access ApplicationUserManager but in this case the shadow properties are in

AppDbContext : IdentityDbContext class.

This is a asp.net core 2 web API project.

Any suggestion is highly appreciated. Thanks

like image 264
WorkInProgress Avatar asked Feb 01 '18 02:02

WorkInProgress


1 Answers

You can get the current user's name using HttpContext.User.Identity.Name. You can access the HttpContext using IHttpContextAccessor. This interface should already be registered in the service collection. Otherwise, you can register it:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    services.AddDbContext<ApplicationDbContext>(options =>
         options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    // ...
}

Then, you can use this interface from the DbContext:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, IHttpContextAccessor httpContextAccessor)
        : base(options)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
    {
        var httpContext = _httpContextAccessor.HttpContext;
        if(httpContext != null)
        {
            var authenticatedUserName = httpContext.User.Identity.Name;

            // If it returns null, even when the user was authenticated, you may try to get the value of a specific claim 
            var authenticatedUserId = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value
            // var authenticatedUserId = _httpContextAccessor.HttpContext.User.FindFirst("sub").Value

            // TODO use name to set the shadow property value like in the following post: https://www.meziantou.net/2017/07/03/entity-framework-core-generate-tracking-columns
        }

        return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
    }
}
like image 102
meziantou Avatar answered Nov 10 '22 04:11

meziantou