Miguel Moura
Miguel Moura

Reputation: 39394

Get current User outside of Controller

On an ASP.NET Core 2.2 controller I have the following:

var principal = this.User as ClaimsPrincipal;

var authenticated = this.User.Identity.IsAuthenticated;

var claims = this.User.Identities.FirstOrDefault().Claims;

var id = this.User.FindFirstValue(ClaimTypes.NameIdentifier);

I am able to check if the user is authenticated and gets the claims including id.

How can I do the same outside of the Controller where I do not have this.User?

Upvotes: 10

Views: 7307

Answers (2)

CodeCaster
CodeCaster

Reputation: 151594

You don't want to inject the IHttpContextAccessor interface into a non-web service, because that gives it a dependency on ASP.NET Core, making it unusable outside the context of a web request.

Instead, resolve the user from within the controller or page you're in:

var user = await _userManager.FindByNameAsync(User.Identity!.Name);

// or by Id
var userId = User.FindFirst(Claims.UserId).Value;
var user = await _userManager.FindByIdAsync(userId);

Now you have an ApplicationUser instance (or whatever you named your Identity user entity), which you can pass to the appropriate service:

await otherService.DoSomething(foo, bar, user);

Upvotes: 2

Nkosi
Nkosi

Reputation: 247123

Inject IHttpContextAccessor interface into the target class. This will give access to the current User via the HttpContext

This provides an opportunity to abstract this feature by creating a service to provide just the information you want (Which is the current logged in user)

public interface IUserService {
    ClaimsPrincipal GetUser();
}

public class UserService : IUserService {
    private readonly IHttpContextAccessor accessor;

    public UserService(IHttpContextAccessor accessor) {
        this.accessor = accessor;
    }

    public ClaimsPrincipal GetUser() {
        return accessor?.HttpContext?.User as ClaimsPrincipal;
    }
}

You need to setup IHttpContextAccessor now in Startup.ConfigureServices in order to be able to inject it:

services.AddHttpContextAccessor();
services.AddTransient<IUserService, UserService>();

and inject your service where needed.

It's important to note that HttpContext could be null. Just because you have IHttpContextAccessor, doesn't mean that you're going to actually be able to always get the HttpContext. Importantly, the code where you're using this must be within the request pipeline in some way or HttpContext will be null.

Credit @ChrisPratt via comment

Upvotes: 24

Related Questions