Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way to get current User ID in Entity Framework Core

There are a bunch of different answers floating around here for the different RC's of ASP.NET Core on how to get the ID of the currently logged in user. I wanted to ask the definite question here. Please note that project.json now has "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0"

With RC1, you could do something like this:

using Microsoft.AspNet.Identity;
using System.Security.Claims;

User.GetUserId();

But with the newly released version 1 of EF Core, Microsoft.AspNet.Identity is not the right version.

There was suggestions to use UserManager, which seems like a lot just to get the currently logged in user:

private Task<ApplicationUser> GetCurrentUserAsync() => _userManager.GetUserAsync(HttpContext.User);

var user = await GetCurrentUserAsync();
var userId = user?.Id;

Another method that I found was:

private readonly UserManager<ApplicationUser> _userManager;
_userManager.GetUserId(User)

So with ASP.NET Core 1 RTM and EF Core 1 with the following libraries in project.json, what is the proper way to get the id of the currently logged in user?

"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0",
like image 780
Reza Avatar asked Jul 23 '16 15:07

Reza


People also ask

How do I get inserted ID for EF core?

EF execute each INSERT command followed by SELECT scope_identity() statement. SCOPE_IDENTITY returns the last identity value inserted into an identity column in the same scope. The above example will execute the following SQL in the database. WHERE @@ROWCOUNT = 1 AND [StudentID] = scope_identity();


Video Answer


3 Answers

If you are accessing this from withing the Controller, then using UserManager to get the user ID is pretty inefficient as you are making a round trip to the database. If you are using ClaimsIdentity, you can do something like this to get the user id:

var claimsIdentity = (ClaimsIdentity)this.User.Identity;
var claim = claimsIdentity.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier);
var userId = claim.Value;

This method just reads the user ID which is already present in the cookie, which in turn is automatically deserialized and stored in a ClaimsIdentity instance.

I use this helper class:

public static class UserHelpers
{
    public static string GetUserId(this IPrincipal principal)
    {
        var claimsIdentity = (ClaimsIdentity)principal.Identity;
        var claim = claimsIdentity.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier);
        return claim.Value;
    }
}

So getting a user ID becomes:

var userId = this.User.GetUserId();

If, for some reason, the required claim is not present in the Claims colleciton, you can easily add it when creating the user's ClaimsIdentity:

public class ApplicaionUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<User> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        userIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, this.UserId));
        return userIdentity;
    }
}
like image 149
Milos Mrdovic Avatar answered Oct 17 '22 16:10

Milos Mrdovic


ASP.NET Core Identity is injected via DI in the startup.cs - as such you just have to inject UserManager via a constructor

UserManager<ApplicationUser> userManager

You can then use the following in methods

_userManager.GetUserId(User);

That's the way its used in the Sample Web Application when you create a new ASP.NET Core 1 project with Individual User Account.

like image 21
Reza Avatar answered Oct 17 '22 15:10

Reza


The one-liner below is a more concise version of the other answers above.

var user = User.FindFirst(ClaimTypes.NameIdentifier).Value;

To explain a little further, I wanted to use the most basic form of authentication without any tables in the database so I chose this one - Using Cookie Authentication without ASP.NET Core Identity from the Core documentation.

To get this working, the first step is to add the services in Startup.cs

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
        {
        options.LoginPath = new PathString("/Account/Login/");
        options.LogoutPath = new PathString("/Account/Logoff/");
        options.AccessDeniedPath = new PathString("/Account/AccessDenied/");
        options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
        });

services.ConfigureApplicationCookie(identityOptionsCookies =>
{
    // See https://andrewlock.net/automatically-validating-anti-forgery-tokens-in-asp-net-core-with-the-autovalidateantiforgerytokenattribute/
    identityOptionsCookies.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
});

Then in the AccountController on the post back having entered a valid user id and password, the simplest Claims based authentication is to just add the login id as a Claim, e.g.

var claims = new List { new Claim(ClaimTypes.NameIdentifier, loginViewModel.Guid, ClaimValueTypes.String, issuer), };

            var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

            var principal = new ClaimsPrincipal(claimsIdentity);

            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal,
                new AuthenticationProperties
                {
                    ExpiresUtc = DateTime.UtcNow.AddMinutes(_cookieTimeoutInMinutes),
                    IsPersistent = true,
                    AllowRefresh = false
                });

Once the Sign In completes you can retrieve the user id as described in the one liner above. See the answer from Milos Mrdovic above for the more detailed steps.

var user = User.FindFirst(ClaimTypes.NameIdentifier).Value;

See Claims-Based Authorization for further information.

like image 28
Andy Creigh Avatar answered Oct 17 '22 16:10

Andy Creigh